矢量迭代器循环使用 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());
我在 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());