繁体   English   中英

使用临时函数获取STL容器的迭代器时出现细微错误:如何避免它?

[英]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 1Statement 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类有一些严重的设计问题:

  1. _map应该更好地封装在类中(用于读取和写入访问),因此可以避免使用getTheMap()方法
  2. 如果确实需要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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM