[英]Subtle error when using temporaries to get iterators to a STL container: how to avoid it?
我们来考虑这个课程:
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
方法应该存在并按值返回。 但是我也在考虑编译器警告。
一种可能性是使用这样的包装:
class X {
typedef std::map<uint32_t,uint32_t> Map;
Map _map;
struct MapWrap {
const Map &mapref;
MapWrap(const Map &mapref_arg)
: mapref(mapref_arg)
{
}
operator Map() const { return mapref; }
};
public:
MapWrap getTheMap()
{
return MapWrap(_map);
}
};
所以你得到这个:
X x;
std::map<uint32_t,uint32_t>::const_iterator iter = x.getTheMap().begin(); // error
std::map<uint32_t,uint32_t> m = x.getTheMap(); // no error
这可以防止意外地像地图一样使用临时,但是使用户必须使用地图的副本。
不是在C ++ 03中。 在C ++ 11中,标准库应该已经启用了这样的保护。
您可以尝试强制getTheMap()通过使用std :: move返回原始对象,但我不确定这是否可行。
如果没有,我想返回成员的唯一/ shared_ptr将是最好的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.