Jackson
Jackson

Reputation: 579

C++ `vector iterators incompatible` error only in Visual Studio

I have a class representing a string of space-delimited words via a vector of those words and an iterator over the vector.

class WordCrawler{
public:
    WordCrawler(std::string, bool reversed=false);
    WordCrawler& operator--();
    std::string operator*  () const;

    bool atBeginning() const;
private:
    std::vector<std::string> words;
    std::vector<std::string>::iterator it;
};

I am trying to print out the words in reverse order, using this function:

void print_in_reverse(std::string in) {
    WordCrawler wc = WordCrawler(in, true);
    while (!wc.atBeginning()) {
        --wc;
        std::cout << *wc << " ";
    } 
}

I construct my WordCrawler object with this constructor:

WordCrawler::WordCrawler(std::string in, bool reversed) {
    std::istringstream iss(in);
    std::string token;
    while (std::getline(iss, token, ' '))
    {
        words.push_back(token);
    }
    if (reversed) {
        it = words.end();
    } else {
        it = words.begin();
    }
}

The rest of the member functions are pretty simple:

/**
 True if pointer is at the beginning of vector
 */
bool WordCrawler::atBeginning() const {
    return it == words.begin();
}

/**
  Function that returns the string stored at the pointer's address
 */
std::string WordCrawler::operator*() const {
    return *it;
}

/**
  Function that increments the pointer back by one
 */
WordCrawler& WordCrawler::operator--() {
    if (!atBeginning())
        --it;
    return *this;
}

I'm finding that everything works fine on Xcode and cpp.sh, but on Visual Studio it throws a runtime error saying vector iterators incompatible at atBeginning() function. My assumption would be that this is because the code is reliant on some sort of undefined behavior, but as I am relatively new to C++ I'm not sure what it is.

I know that it is always an iterator of the words vector, and I know that words does not change after it has been initialized, so I'm not sure what the issue is.

Full code at: http://codepad.org/mkN2cGaM

Upvotes: 2

Views: 2158

Answers (1)

M.M
M.M

Reputation: 141586

Your object has a rule of three violation - on copy/move construction the iterator will still point to the vector in the old object.

The line WordCrawler wc = WordCrawler(in, true); specifies a copy/move operation, triggering this problem. Most compilers perform copy elision here but I heard that older versions of MSVC don't, in debug mode anyway.

To fix this properly, I would recommend using an index instead of an iterator in the class. If you really want to use the iterator you will need to implement your own copy-constructor and move-constructor.

Changing that line to WordCrawler wc(in, true); would probably fix this particular program but the same problem would be lurking still, and might show up when you make further modifications later.

Upvotes: 4

Related Questions