1

让我们考虑这个类:

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 1and中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有一些严重的设计问题:

  1. _map应该更好地封装在类内部(用于读写访问),因此getTheMap()可以避免该方法
  2. 如果getTheMap()确实需要该方法,它可以返回对_map

但是,给定 X 类“原样”(<-- 请参阅下面的编辑),有没有办法阻止用户将迭代器获取到临时的?

编辑:类X可以更改,但getTheMap方法应该存在并按值返回。但是我也在考虑编译器警告。

4

3 回答 3

2

一种可能性是使用这样的包装器:

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

这可以防止意外使用临时地图,但使其在用户必须使用地图副本的地方。

于 2012-03-21T14:47:51.353 回答
1

不在 C++03 中。在 C++11 中,标准库应该已经启用了这种保护。

于 2012-03-21T14:57:10.857 回答
0

您可以尝试使用 std::move 强制 getTheMap() 返回原始对象,但我不确定这是否适用。

如果没有,我想返回成员的 unique/shared_ptr 将是最好的选择。

于 2012-03-21T15:19:56.293 回答