patterncppMinor
Sieve prime generator C++
Viewed 0 times
primesievegenerator
Problem
I had some issues with the behavior of the iterator in my prime generator:
I think erasing an element of
#include
#include
#include
using namespace std;
int main() {
int a,b;
int nbr;
vector t;
set s;
// prime generated to b
b = 10;
// set 2 -> b.
for (int i = 2; i != b; i++)
{
s.insert(i);
}
int i = 0;
while (s.size() != 0)
{
i++;
cout ::iterator it = s.begin() ; it != s.end(); it++)
{
cout ::iterator it = t.begin() ; it != t.end(); ++it)
{
cout << "t = " << *it << endl;
}I think erasing an element of
s in the for loop can be a problem, but the compiler doesn't complain and it seems to work. Is it a problem? I am also happy for a general review.Solution
Here are some things that may help you improve your code.
Eliminate unused variables
Unused variables are a sign of poor quality code, and you don't want to write poor quality code. In this code,
Avoid single-line
The compiler can handle it just fine, but readers of your code are more likely to be able to correctly interpret the code if you avoid single-line
use this
Be careful when you
The standard, in section 23.2.4 says that for an associative container, when you use
erases the element pointed to by q. Returns an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists, returns a.end().
This means that to be safe, your loop should look like this instead:
As pointed out by @LokiAstari, this works just fine for associative containers such as
This works with
Think carefully about signed and unsigned
The code currently uses
Reconsider container choices
A
Consider using range-for syntax
The code currently prints the resulting
It can be written much more simply with a range-for:
Don't use
Using
Eliminate unused variables
Unused variables are a sign of poor quality code, and you don't want to write poor quality code. In this code,
a and nbr are unused. Your compiler is smart enough to tell you about this if you ask it nicely.Avoid single-line
if constructsThe compiler can handle it just fine, but readers of your code are more likely to be able to correctly interpret the code if you avoid single-line
if. So instead of if (*it % t.back() == 0) {s.erase(it++);}use this
if (*it % t.back() == 0) {
s.erase(it++);
}Be careful when you
erase an iteratorThe standard, in section 23.2.4 says that for an associative container, when you use
erase(it) where it is an iterator:erases the element pointed to by q. Returns an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists, returns a.end().
This means that to be safe, your loop should look like this instead:
for (auto it = s.begin() ; it != s.end(); )
{
cout << " s = " << *it << '\n';
if (*it % t.back() == 0)
it = s.erase(it);
else
++it;
}As pointed out by @LokiAstari, this works just fine for associative containers such as
std::set but a more generic approach would be to use this for the line containing erase:s.erase(it++);This works with
set but also with other non-associative standard containers, including vector.Think carefully about signed and unsigned
The code currently uses
int types for both the vector and the set but are you looking for negative prime numbers? If not, it could be that unsigned would be a better choice for data type.Reconsider container choices
A
std::set is a sorted associative container. Since it's usually implemented internally as a tree, it's a relatively computationally expensive container to use consider the fact that all you really need is a list. Consider using range-for syntax
The code currently prints the resulting
vector with this code:for (vector::iterator it = t.begin() ; it != t.end(); ++it)
{
cout << "t = " << *it << endl;
}It can be written much more simply with a range-for:
for (const auto i : t) {
cout << "t = " << i << '\n';
}Don't use
std::endl if '\n' will doUsing
std::endl emits a \n and flushes the stream. Unless you really need the stream flushed, you can improve the performance of the code by simply emitting '\n' instead of using the potentially more computationally costly std::endl.Code Snippets
if (*it % t.back() == 0) {s.erase(it++);}if (*it % t.back() == 0) {
s.erase(it++);
}for (auto it = s.begin() ; it != s.end(); )
{
cout << " s = " << *it << '\n';
if (*it % t.back() == 0)
it = s.erase(it);
else
++it;
}s.erase(it++);for (vector<int>::iterator it = t.begin() ; it != t.end(); ++it)
{
cout << "t = " << *it << endl;
}Context
StackExchange Code Review Q#71485, answer score: 6
Revisions (0)
No revisions yet.