【发布时间】:2012-04-06 01:24:47
【问题描述】:
让我们考虑这个类:
class X {
std::map<uint32_t, uint32_t> _map;
public:
X() { /* Populate the map */ }
std::map<uint32_t, uint32_t> getTheMap() { return _map; }
};
还有这个错误的代码:
X x;
// Statement 1
std::map<uint32_t, uint32_t>::const_iterator it = x.getTheMap().begin();
// Statement 2
std::map<uint32_t, uint32_t>::const_iterator et = x.getTheMap().end();
for (; it != et; it++) {
/* Access the map using the iterator it */
}
错误的部分是,在Statement 1 和Statement 2 中,我得到了一个临时对象的迭代器,该对象将在每个语句的末尾被销毁。
因此,for() 循环内的行为未定义。
getTheMap() 方法的正确用法应该是这样的:
std::map<uint32_t, uint32_t> map = x.getTheMap();
std::map<uint32_t, uint32_t>::const_iterator it = map.begin();
std::map<uint32_t, uint32_t>::const_iterator et = map.end();
for (/* [...] */)
必须注意,X 类有一些严重的设计问题:
-
_map应该更好地封装在类中(用于读写访问),因此可以避免使用getTheMap()方法 - 如果确实需要
getTheMap()方法,它可以返回对_map的引用
但是,给定 X 类“按原样”(
编辑:X 类可以更改,但getTheMap 方法应该存在并按值返回。但是我也在考虑编译器警告。
【问题讨论】:
-
如果不能更改 X 类,我们必须处理什么?可以隐藏类 X,迫使用户使用其他东西,比如包装类吗?
-
文档怎么样。
-
@VaughnCato 你是完全正确的:)。我在问题末尾的
EDIT部分添加了一条注释。 -
继续按值返回的原因是什么?返回对 const 的引用和引用不会破坏旧代码。
-
你不能做任何事情,除了重新设计类以不蹩脚。如果用户没有意识到这一点,他们不应该编写 C++。另外,如果您通过引用返回地图,您不妨将
_map公开。
标签: c++ stl iterator temporary-objects