我是如何设法在标准容器中存储引用类型的?

时间:2014-07-09 13:40:15

标签: c++ c++11 reference copy-constructor

在尝试使用C ++ 11智能指针和容器类时,我编写了两段代码,基本上归结为以下内容:

class Foo { ... };
typedef std::unique_ptr<Foo> FooPtr;

// First attempt; this did _not_ compile
typedef std::unordered_map<int, FooPtr> IntToFooMap;

// Second attempt; this _did_ compile
typedef std::unordered_map<int, const FooPtr &> IntToFooMap;

// here is the declaration causing the error in the second case:
IntToFooMap m {
    { 41, FooPtr(new Foo()) }
};

正如您所看到的,首先我尝试定义无法编译的FooPtr的无序地图,因为FooPtrstd::unique_ptr,它不可复制(它有一个删除了复制构造函数)。

更确切地说,它是使用导致错误的初始化列表初始化地图。

然而,令我惊讶的是,第二个版本,即我将无序地图的value_type定义为FooPtr const引用,确实已编译。

直到今天,我认为通常不可能在标准容器中存储引用类型的值。虽然这种行为在某种程度上是直观易懂的,但由于声明一个(const)引用会阻止 - {禁止 - 复制unique_ptr,我仍然不完全理解这是如何工作的原因。 如果它完全有效, 当然;如果这只是一个导致未定义行为的微妙角落,我不会感到惊讶。

1 个答案:

答案 0 :(得分:3)

您违反了图书馆的约束。这导致未定义的行为。图书馆可能会也可能不会发现它是参考文献。

引用的问题是允许库假定容器拥有保存元素值的对象,因此调用它的析构函数,特别是它可以这样做:

allocator_traits<A>::destroy(m, p) // m is the allocator, p points to object.

我没有注意到语言明确要求std::[unordered_]map中的映射类型是对象类型,但是你必须非常小心避免operator[]试图默认构造value_type std::pair<int, FooPtr const &>。对于无序容器,还需要value_type的CopyAssignability,以便将动态数组用作散列桶,虽然引用是CopyAssignable(副本转换为引用的对象),但是包含引用的对不是。

我怀疑图书馆的意图是允许那里的参考,但是可能缺少禁令。无论如何,我现在很困。也许有人可以找到它。