矢量迭代器循环使用 g++ 而不是 VisualC++,为什么?

Vector iterator loop working with g++ but not VisualC++, why?

我在 linux 机器上写了一个程序。它使用 std::vector<std::string> 并且我用 for 循环遍历它

std::vector<std::string> words;
words.push_back("A");
words.push_back("B");
words.push_back("C");
// loop
for (auto it = words.end(); it >= words.begin(); it--)
{
    std::string word = *it; // invalid deref?
    // do things with word
    if (word == "B")
    {
        words.erase(it);
    }
    std::cout << word << std::endl;
}

int i = 0;
for (std::string word : words)
{
    std::cout << i++ << word << std::endl;
}

这 运行 如预期的那样使用 g++ 作为编译器,打印 C、B 和 A。但是当我 运行 使用 VisualStudio 时,我得到一个无效的取消引用异常。

我 运行 向后遍历向量,因为我想从中删除项目,如果向前循环,迭代器就会混乱。
我有一个使用整数并使用 std::vector<std::string>.at(int) 获取项目的解决方法,但我很好奇为什么这适用于我的 linux 机器而不是 windows?

为你的迭代尝试这个

for (auto it = words.rbegin(); it != words.rend(); it++)

代码通过 words.erase(it); 使循环中的迭代器无效。 std::vector<>::erase 使擦除点或擦除点之后的迭代器和引用无效,包括 end() 迭代器。

删除匹配元素的一种安全方法是:

words.erase(std::remove(words.begin(), words.end(), "B"), words.end());

完整版:

std::vector<std::string> words;
words.push_back("A");
words.push_back("B");
words.push_back("C");

words.erase(std::remove(words.begin(), words.end(), "B"), words.end());

int i = 0;
for (std::string word : words)
    std::cout << i++ << ' ' << word << '\n';

正如您正确评论的那样,存在无效的解除引用。

std::string word = *it;

在第一次迭代中将是 std::string word = *words.end(),这会导致未定义的行为。所以它在一个系统上工作并在另一个系统上抛出异常是完全有效的。

反向迭代向量的正确方法是

for(auto it = words.rbegin(); it != words.rend(); it++) {...}

但是,对于从向量中删除元素,erase-remove-idiom 可能更有用:

words.erase(std::remove(words.begin(), words.end(), "B"), words.end());

或者,如果您有更复杂的条件,请使用 lambda:

words.erase(std::remove_if(
   words.begin(), 
   words.end(), [](const std::string &name){return name == "B";}
), names.end());