仅在 Visual Studio 2010 中存在可延迟迭代器的问题
Posted
技术标签:
【中文标题】仅在 Visual Studio 2010 中存在可延迟迭代器的问题【英文标题】:Problem with a deferencable iterator only with visual studio 2010 【发布时间】:2011-08-19 10:00:12 【问题描述】:我有这段代码可以删除我的std::vector
中的某些元素:
splitVector.erase(splitVector.begin());
if ( (splitVector.end())->length() == 0 )
splitVector.erase(splitVector.end());
这段代码在 MacOs 上运行良好,但在 windows 上它只会给我这个错误:
表达式:向量迭代器不可延迟
我不明白为什么这个操作适用于一个操作系统而在另一个操作系统上会出错,因为它非常基本。
任何人都知道为什么会发生这种情况?
我还应该继续使用std::vector
还是转移到其中一个 boost 容器?
谢谢
【问题讨论】:
应该将splitVector
推定为std::vector<T*>
,其中T::length()
存在?
【参考方案1】:
您需要意识到 vector::end 不是向量中的最后一项。这是最后一项的过去。如果您尝试取消引用它,那么您的程序就会出错。 Windows 很有帮助地告诉你这一点,MacOS 没有帮助。建议您阅读如何在标准库中使用容器和迭代器。如果您不了解基础知识,那么转向 boost 不太可能对您有所帮助。
也许你想要做的是这个
if ((splitVector.end() - 1)->length() == 0)
splitVector.erase(splitVector.end() - 1);
【讨论】:
我想我活该。谢谢 擦除开始后,不要忘记检查end() - 1
是否仍然存在。向量可能为空!
@Lollancf37:对不起,我的语气真的很烂。
我已经检查了向量是否为空,谢谢大家。 @john 不用担心,除了您的回复快速准确,再次感谢。【参考方案2】:
像std::vector<T>
这样的容器定义了半开范围,即end()
迭代器指向内存在最后一个元素之后。这意味着,没有可延迟的对象。
你想做的大概是
if (!splitVector.empty() && splitVector.back().empty())
splitVector.pop_back();
注意在访问元素之前对非空向量的额外测试。
【讨论】:
【参考方案3】: if ( (splitVector.end())->length() == 0 )
这只是调用未定义行为 (UB),因为 end()
返回的 iterator
是不可取消引用的。
它可以在一个平台上运行,而不能在另一个平台上运行正是因为它的 UB 意味着任何事情都可能发生;有无数种可能性,但语言规范都不保证这些可能性。
另外,splitVector.end()
不是 last 元素的迭代器。它的 past-the-last-element 迭代器。你真正想要的是这样的:
splitVector.erase(splitVector.begin());
if(!splitVector.empty() && (splitVector.begin() + splitVector.size()-1 )->length() == 0 )
splitVector.erase(splitVector.begin() + splitVector.size() - 1);
【讨论】:
谢谢,我会继续写这本书的。 @Nawaz:如果splitVector
在erase
之后为空,则您仍在UB。
@Matthieu:哎呀。我没有检查那个。已编辑。 :-)
@Nawaz:这就是为什么我非常感谢 Dirkunmare 团队在他们的 STL 中引入了如此多的调试检查,这绝对是太容易搞砸了:/
@Nawaz:Dirkumware(不是 Dirunmare ...)是 MSVC STL 的来源公司(我认为是在改编之前)。他们煞费苦心地对标准提到的所有 Undefined Behavior (迭代器无效、范围验证等)添加补充检查(如 OP 显示的断言)。例如,请参阅:msdn.microsoft.com/en-us/library/aa985965%28v=VS.80%29.aspx 处的 Checked Iterators(警告,它可能会大大减慢程序速度)【参考方案4】:
有两个错误,一个已被大量评论:
vector.end()->foo()
调用未定义的行为。
另一个更间接:
vector.erase(vector.begin());
在end
迭代器上调用erase
(UB) 是错误的,如果vector
为空 然后vector.begin() == vector.end()
,调用UB。
此错误再次出现在if
的正文中。
据我所知,您要查找的内容类似于:
if (!vector.empty()) vector.pop_front();
if (!vector.empty() && vector.back().length == 0) vector.pop_back();
请注意,vector
上有一些惯用的方法,它们不允许你摆弄那些笨拙的向量,还要注意这里使用的那些需要非空向量才能工作。
【讨论】:
以上是关于仅在 Visual Studio 2010 中存在可延迟迭代器的问题的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 代码分析 (fxCop) 仅在第一次构建后运行
使用TFS 2010在Visual Studio 2012中进行代码审查
Visual Studio 2010 程序集签名:尝试引用不存在的令牌