-2

I have a problem when my application crashes with this error message from VS: "Debug assertion failed! (...) Expression: vector iterator not dereferencable".

The thing is, it happens during using vector's push_back.

Here is the code. It is my BigInt library, that I decided to implement as an exercise. The bug is hidden in my TestBigInt class, that I created to (surprisingly) test BigInt. The code is admittedly quite long, but I narrowed the bug to a single piece of that. This is the input I give to the bugged code:

/* "BigIntTestCases.txt": format { label num1 num2 autoChecked { } }
* { 1 3 2 1 { } }
* { 2 10 7 1 { } }
* { 3 21 9 1 { } }
* ...
*/
    int main() {
        ifstream ifs{ "BigIntTestCases.txt" };
        // read tests into vector<BigIntTest>
        for (auto it = tests.begin(); it != tests.end(); ++it) {
            std::cout << "Read: " << it->label << ' ' << it->num1 << ' ' << it->num2 << ' ' << it->autoChecked << '\n';
            performTest(ofs, (*it));
        }
    }

That gives me output:

Read: 1 3 2 1
pushed_back exResults
pushed_back outResults
Read: 2 10 7 1
pushed_back exResults
CRASH

This is "TestBigInt.cpp", and here lies the bug (in the first 4 push_backs of the first function - doTests()):

void TestBigInt::doTests()
{
    // fill outResults - vector of BigInt test results
    BigInt firstNum{ num1 };
    BigInt secNum{ num2 };

    outResult.push_back((firstNum + secNum).toString());
    outResult.push_back((secNum + firstNum).toString());
    outResult.push_back((firstNum - secNum).toString());
    outResult.push_back((secNum - firstNum).toString());
    outResult.push_back((firstNum * secNum).toString());
    outResult.push_back((secNum * firstNum).toString());
    std::cout << "pushed_back outResults\n";
}
void TestBigInt::autoFillExR()
{
    // fill vector exReults -- expected results
    int firstNum = stringToI(num1);
    int secNum = stringToI(num2);

    exResult.push_back(iToString(firstNum + secNum));
    // ... - essentialy the same as doTest()
    std::cout << "pushed_back exResults\n";
}
std::ostream& performTest(std::ostream& os, TestBigInt& t)
{   
    if (t.autoChecked) // if the results are to be autochecked, than fill the exResult -- else it is already full
        t.autoFillExR();

    t.doTests();

    for (auto itE = t.exResult.cbegin(), itO = t.outResult.cbegin(); itE != t.exResult.cend() && itO != t.outResult.cend(); ++itE, ++itO)
        if (*itE != *itO)
            os << "Test not passed: " << t.label  << ", " << distance(t.exResult.cbegin(), itE) << "\n\tExpected: " << *itE << ", got " << *itO << "\n";

    return os;
}

This is implementation of BigInt::toString

std::string BigInt::toString() const
{
 // the digits are stored in "reversed order", i.e. digits[0] is the least significant digit
    std::string num;
    if (sign == Sign::negative)
        num += "-";
    for (auto it = digits.crbegin(); it != digits.crend(); ++it)
        num += ('0' + *it);
    return num;
}

I do know that it is extremely long sample, but at least I narrowed the bug by quite a bit. Frankly I have no idea why it does not work.

A big thank you to anyone that read through this post. If you have any ideas about why it could be wrong, than please do post it here -- I'm quite helpless, and would appreciate any help

MeyCJey
  • 5
  • 2
  • http://stackoverflow.com/help/mcve – Lightness Races in Orbit May 25 '15 at 19:46
  • 1
    1. This problem might have been already solved: [Google search - vector iterator not dereferencable](https://www.google.com/search?&hl=en&q=vector+iterator+not+dereferencable). – Ivan Aksamentov - Drop May 25 '15 at 19:49
  • 1
    2. Use [debugger](https://www.google.com/search?name=f&hl=en&q=vector+iterator+not+dereferencable&gws_rd=ssl#hl=en&q=debugger++c%2B%2B) to narrow down error to a single line. – Ivan Aksamentov - Drop May 25 '15 at 19:50
  • 3. Please click this link only if you are desperate and links above don't help: [Iterator invalidation rules](http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – Ivan Aksamentov - Drop May 25 '15 at 19:54
  • 1. It doesn't seem like the problem has been solved -- the links pointed to mainly talk about dereferencing a failed find(), or using iterator after using erase(). My problem seems to bee neither of those. 2. Basically I have -- 4 of those 6 push_backs are causing the crash on their own (all besides the * ones) – MeyCJey May 25 '15 at 19:55
  • 3. As I said, I have not used erase(), and insert() either. – MeyCJey May 25 '15 at 20:04
  • [push_back](http://en.cppreference.com/w/cpp/container/vector/push_back) might invalidate iterators as well. Also, I think this: `itE != t.exResult.cend() && itO != t.outResult.cend()` could lead to dereferencing of [`end`](http://en.cppreference.com/w/cpp/container/vector/end) (and possibly beyond) if containers have different lenghts. You should really REALLY use debugger to know for sure. – Ivan Aksamentov - Drop May 25 '15 at 20:31

1 Answers1

0

You can't iterate through a vector while pushing back, as push_back may invalidate iterators.

I can't see the problem mentioned here above in the posted code though (refer code), hence I retract the answer above. I've based it on assumptions prior to seeing all the code.

However, given this code:

for (TestBigInt t; ifs >> t; )
        tests.push_back(t);

Are you aware that you are always modifying the same instance of t. You are pushing copies, but operator >> always modifies the original instance, growing its vector. Is this what you want? Your amount of results then exceed 6...

Werner Erasmus
  • 3,702
  • 14
  • 27
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/78803/discussion-on-answer-by-werner-erasmus-vector-iterator-not-dereferencable-error). – Taryn May 26 '15 at 12:37