临时容器对象上的迭代程序
Iterators on temporary container object
假设我有一个函数,它按值返回STL容器,比如std::list
std::list<Foo> get_Foolist()
{
std::list<Foo> lst;
//populate lst
return lst;
}
或
class SomeClass
{
std::list<Foo> get_Foolist()
{
return m_foolst;
}
...
private:
std::list<Foo> m_foolst;
};
现在,我有一段代码,它使用这个函数来获取列表,并以以下方式对其进行迭代,
std::list<Foo>::iterator i = get_Foolist().begin();
//use i like ... cout << *i << endl;
当我看到这段代码时,我觉得它不应该工作,因为我们在一个临时对象上使用迭代器,这个对象将在表达式执行后被删除。但是,令我惊讶的是,它起了作用。
这与STLPort5.2和Microsoft Visual Studio 2008配合使用。
后来,当我们删除STLPort并开始使用编译器提供的STL实现时,我们开始面临崩溃。
据透露,上面的代码不适用于VS2008列表实现,但它适用于STLPort。
我试着在其他各种编译器上运行它,结果如下,
- Visual Studio 2008(不带STLport5.2)-崩溃
- Visual Studio 2008(带STLPort5.2)-工作
- Visual Studio 2013(不带STLport5.2)-崩溃
- GCC 4.3.6(不含STLPort5.2)-工程
- Clang 3.0(不带STLPort5.2)-工程
(GCC和Clang来自http://melpon.org/wandbox/)
现在我的问题是,
- 哪个实施是正确的(根据标准)
- 为什么它在VS之外的所有实现上都成功了
- 哪个实施是正确的(根据标准)
大概都是吧。
- 为什么它在VS之外的所有实现上都成功了
这是未定义的行为,因为您正在取消引用无效的迭代器。因此,它可能会以无数种方式失败。或者看起来有效,这只是另一种失败模式。
在C++中有许多哲学设计规则(其中一些规则告诉一个规则与另一个规则相反),但一个经常应用的规则是"信任程序员"。
这个规则允许实现者简单地忽略程序员方面的错误:当你写的代码出错时(比如删除一个对象两次,或者迭代一个不再存在的容器),编译器可以自由地忽略会发生的事情,而不是引发运行时错误。这就是所谓的"未定义行为"。
其原理是,你永远不会这样做,在运行时浪费哪怕只是一纳秒来检查这些情况是否发生也不值得。
如果你因为操作系统阻止了你分配的虚拟地址空间之外的访问而立即崩溃,你可以认为自己非常幸运。
如果你得到一个随机值,显示疯狂的结果,你仍然可以认为自己很幸运。。。不幸的是,有时你会得到一个"合理"的结果,这会在很长一段时间内隐藏错误,因为错误的代码会做"正确的事情",因此程序员会继续实现其他功能,并在错误的代码上添加更多的代码。
换句话说,"未定义的行为"意味着任何事情都可能发生,包括什么都不发生。
通常情况下,只有当损坏程度很高时(即,当代码正在生产中,而您正忙于处理愤怒的客户时),代码才会失败。
- C++中的Constexpr迭代程序
- 双向迭代程序的decltype(*it)是什么
- c++迭代程序在向量上迭代时崩溃
- MergeSort.使用迭代程序实现
- 类中的C++迭代程序没有将结构作为类型
- 不带迭代程序的哈希映射循环
- C++迭代程序访问下一个元素进行比较
- 重载运算符==具有采用模板化迭代程序的自由函数
- 使用反向迭代器插入std::list会更改原始反向迭代程序的值
- 临时容器对象上的迭代程序
- 矢量迭代程序不兼容(分段错误)
- 迭代程序在C++中的重要性
- 有效或无效的迭代程序和迭代程序位置
- 迭代程序取消引用
- C++迭代程序异常安全
- 我的常量和非常量链表迭代程序有何不同
- 调用擦除后迭代程序无效
- 事件管理器中游戏的迭代程序在注销时失效
- 矢量迭代程序的增量/减量
- Deque迭代程序错误