Click to See Complete Forum and Search --> : vector iterator not dereferencable


chris_t_morin
July 16th, 2008, 08:51 AM
I tried to run a program that compiled correctly and I get an error message:

Debug Assertion Failed!
...
Expression: vector iterator not dereferencable
...


What does this mean and why does it say a vector iterator isn't dereferencable?

thanks

Graham
July 16th, 2008, 08:55 AM
We could do with a few more hints. Personally, I've had to turn my telepathy off, since it was wasting to much energy.

However, I'll stick my neck out and say that you're attempting to dereference an iterator that's either not been set or is equal to vector::end().

chris_t_morin
July 16th, 2008, 09:28 AM
I thought that might not be enough to work with. but i just learned something.
I compiled the program with Dev-C++ and it worked flawlessly. Its only when I was compiling with Visual Studio 2008 that it didn't work.
I guess that means that the iterators are fine (at least according to Dev-C++).

Philip Nicoletti
July 16th, 2008, 09:33 AM
I thought that might not be enough to work with. but i just learned something.
I compiled the program with Dev-C++ and it worked flawlessly. Its only when I was compiling with Visual Studio 2008 that it didn't work.
I guess that means that the iterators are fine (at least according to Dev-C++).

No ... it just means that the code did not crash under dev-C++.
Newer versions of the Microsoft compiler have additional checks
that make sure that the iterator is valid.

There is almost certainly a coding problem. Can you post a
small code snippet that reproduces the problem ?

Paul McKenzie
July 16th, 2008, 10:02 AM
I guess that means that the iterators are fine (at least according to Dev-C++).No.

If you ever have the case where the code "works" using one compiler, and crashes using another compiler, you *always* suspect that there is something wrong with the coding.

Accessing an invalid iterator is undefined behaviour. This means that the code can seem to work, or the code can crash, or the code may crash later, or anything can happen.

If compiling and running with a certain compiler reveals a problem, be lucky that the compiler caught your bad coding. Otherwise you would be running an app that has a bug without you knowing it.

Regards,

Paul McKenzie

chris_t_morin
July 16th, 2008, 10:24 AM
I hope 75 lines is a small code snippet


#include <iostream>
#include <vector>

using namespace std;

class reader
{
public:
reader()
{
strcpy(text,"7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450");
for(int i=0;i!=1001;++i)
{
int t = text[i];
numbers.push_back(t-48);
}

five[0]=numbers.begin();
five[1]=(numbers.begin()+1);
five[2]=(numbers.begin()+2);
five[3]=(numbers.begin()+3);
five[4]=(numbers.begin()+4);

}
void next()
{
++five[0];
++five[1];
++five[2];
++five[3];
++five[4];
}

long get()
{
return ((*five[0])*(*five[1])*(*five[2])*(*five[3])*(*five[4]));
}
private:
char text[1001];
vector<int> numbers;
vector<int>::iterator five[5];
};

class prod
{
public:
prod()
{
for(int i=0;i<999;++i)
{
product[i]=book.get();
book.next();
}
}
long highest()
{
long big=0;
for(int i=0;i<999;++i)
{
if(product[i]>big)
big=product[i];
}
return big;
}
private:
long product[998];
reader book;
};

int main()
{
prod bla;
cout<<bla.highest()<<endl;
system("pause");
}

dude_1967
July 16th, 2008, 10:34 AM
Something is going wrong with your complicated indexes.

You should make more significant use of the power and elegance of the C++ STL for your conversions.

You will get off to a better start if you begin to study and understand this code:


#include <string>
#include <vector>

int main(void)
{
const std::string str_numbers("7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450");

std::vector<int> int_numbers(str_numbers.size());

const std::size_t sz = str_numbers.size();

for(std::size_t i = 0u; i < sz; i++)
{
int_numbers[i] = static_cast<int>(str_numbers.at(i) - static_cast<char>(48));
}
}

Philip Nicoletti
July 16th, 2008, 10:42 AM
in the constructor for prod ... as i gets close to 999, it
seems like book.next() will result in iterating past end().

Try changing to:


void next()
{
if (five[0] != numbers.end()-1) ++five[0];
if (five[1] != numbers.end()-1) ++five[1];
if (five[2] != numbers.end()-1) ++five[2];
if (five[3] != numbers.end()-1) ++five[3];
if (five[4] != numbers.end()-1) ++five[4];
}

chris_t_morin
July 16th, 2008, 10:59 AM
@Dude
What is complicated indexes?
I understand that code but I wouldn't have been able to write it yet. regardless, my problem doesn't seem to be with the vector but with the iterator. another error message that i missed before but that shows up right after the first is:
Expression: ("Standard C++ Libraries Out of Range", 0)

@Philip
Cool, that works. Thanks

Paul McKenzie
July 16th, 2008, 11:07 AM
I hope 75 lines is a small code snippet

strcpy(text, ".....");
for(int i=0;i!=1001;++i)
//...
char text[1001];
So you actually counted, and verified that text is 1001 characters?? No programmer does this, the reason is that we're human beings, and manually counting 1,001 characters is very error-prone and risky. What if you're counting is off by a single byte?

Let the computer do the counting, not fragile human eyes and hands. You should have been using strlen() in this case, not hard-coding 1001.

Second, why is text a char array, when it could easily have been a std::string?

text = "whatever";
//...
std::string text;

All of these points, plus what others have mentioned, prevents errors of using invalid iterators, memory overwrites, etc.

Regards,

Paul McKenzie

dude_1967
July 16th, 2008, 11:09 AM
Chris,

The complexity issue here does not jump right out in your face, but rather lurks around and causes problems later in the most inopportune of all situations, like after a minor change.

I am talking about lines like this: for(int i=0;i!=1001;++i) as well as lines like this: for(int i=0;i<999;++i)

As soon as you change the size of your string, or maybe some other analysis parameters, then you have to synchronize this change with several index-range numbers in the various loops of your program. This is a design element which can very quickly lead to problems if you need to change your software or write a flexible interface. For example you might remember to change the 1001 and forget to change the 999.

By using STL containers effectively you can always use the member function size() in order to find out the right loop-range.

I had suspected that you would understand my code. And I suspect that Philip took a look at your code and asked himself, "How far do I want to go with this chris_t_morin guy". He decided to simply help you with the issue at hand within your framework. However, I recommend that you actually begin to use containers more consistently. In the long run your coding quality and the stability of your programs will greatly benefit from this.

Good luck. :thumb:

Sincerely, Chris.

chris_t_morin
July 16th, 2008, 11:36 AM
I understand what your saying and will try to adapt my code to it but I just wanted to pinpoint the source of my error and I was mostly confused cause it worked wit one compiler and not the other so i assumed the compiler was wrong.
Anyways thanks alot for your time and help.

Lindley
July 16th, 2008, 12:26 PM
I understand what your saying and will try to adapt my code to it but I just wanted to pinpoint the source of my error and I was mostly confused cause it worked wit one compiler and not the other so i assumed the compiler was wrong.
Anyways thanks alot for your time and help.

Rule of thumb: Until you actually examine the generated assembly code and determine that what it is trying to do is not what you want it to do, always assume the compiler is right, and you are wrong.

It's not impossible for the compiler to screw up....but it's extremely rare.

Graham
July 16th, 2008, 01:53 PM
Another thing to point out (it's not a problem with the existing code, but it will bite you in the future if you carry on this way): never hold iterators into a vector for longer than is absolutely necessary. You're storing them in member variables - at some point in the future, you will modify the vector after storing those iterators and that modification will invalidate all of them. Much better to store some other information that will allow you to get the iterators fresh at the point you need them.

for example:

class reader
{
public:
reader()
{
strcpy(text,"7316717...");
for(int i=0;i < strlen(text);++i)
{
numbers.push_back(text[i] - '0');
}
base_index = 0;
}
void next()
{
++base_index;
}

long get()
{
if (base_index > numbers.length() - 5)
return -1;

typedef vector<int>iterator it;
it it0 = numbers.begin() + base_index;
it it1 = it0 + 1;
it it2 = it1 + 1;
it it3 = it2 + 1;
it it4 = it3 + 1;
return ((*it0)*(*it1)*(*it2)*(*it3)*(*it4));
}
private:
char text[1001];
vector<int> numbers;
int base_index;
};


Note that there are still several problems with this class, not least of which is that I wouldn't bother with iterators at all:


long get()
{
return (numbers[base_index]*numbers[base_index+1]*numbers[base_index+2]*numbers[base_index+3]*numbers[base_index+4]);
}