我通过定义
在应用程序中启用了迭代器调试_HAS_ITERATOR_DEBUGGING = 1
我期待这真的只是检查矢量边界,但我感觉它做的远不止于此。实际上正在进行哪些检查等?
顺便说一下,Dinkumware STL。答案 0 :(得分:10)
迭代器有许多操作会导致未定义的行为,此触发器的目标是激活运行时检查以防止它发生(使用断言)。
问题
显而易见的操作是使用无效的迭代器,但这种无效性可能由以下各种原因引起:
vector
)[begin, end)
标准精确的每个容器的难以忍受的细节,哪个操作使迭代器无效。
有一个不太明显的原因,人们往往会忘记:将迭代器混合到不同的容器:
std::vector<Animal> cats, dogs;
for_each(cats.begin(), dogs.end(), /**/); // obvious bug
这涉及一个更普遍的问题:传递给算法的范围的有效性。
[cats.begin(), dogs.end())
无效(除非一个是另一个的别名)[cats.end(), cats.begin())
无效(除非cats
为空?)解决方案
解决方案在于向迭代器添加信息,以便在执行期间可以断言它们的有效性和它们定义的范围的有效性,从而防止发生未定义的行为。
_HAS_ITERATOR_DEBUGGING
符号用作此功能的触发器,因为它不幸地减慢了程序的速度。它在理论上非常简单:每个迭代器都是它发出的容器的Observer
,因此被通知修改。
在Dinkumware中,这是通过两个补充来实现的:
这巧妙地解决了我们的问题:
费用
成本很高,但正确性是否有代价?我们可以分解成本:
O(NbIterators)
O(NbIterators)
(请注意,push_back
或insert
不一定会使迭代器失效,但erase
会失效O( min(last-first, container.end()-first) )
当然,大多数库算法都是为了最大效率而实现的,通常在算法开始时一次性完成检查,然后运行未经检查的版本。然而速度可能会严重减慢,特别是手写循环:
for (iterator_t it = vec.begin();
it != vec.end(); // Oups
++it)
// body
我们知道 Oups 行很糟糕,但更糟糕的是:在循环的每次运行中,我们创建一个新的迭代器然后销毁它,这意味着为{{分配和取消分配节点1}}的迭代器列表...我是否必须强调在紧密循环中分配/释放内存的成本?
当然,vec
不会遇到这样的问题,这是使用STL算法而不是手动编码版本的另一个令人信服的理由。
答案 1 :(得分:0)
据我所知:
_HAS_ITERATOR_DEBUGGING将在运行时显示一个对话框,以断言任何不正确的迭代器使用,包括:
1)删除元素后在容器中使用的迭代器
2)调用.push()或.insert()函数后向量中使用的迭代器
答案 2 :(得分:0)
根据http://msdn.microsoft.com/en-us/library/aa985982%28v=VS.80%29.aspx
C ++标准描述了哪些成员函数导致容器的迭代器变为无效。两个例子是:
- 从容器中删除元素会导致元素的迭代器变为无效。
- 增加向量的大小(推送或插入)会导致向量容器中的迭代器变为无效。