在尝试使用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
的无序地图,因为FooPtr
是std::unique_ptr
,它不可复制(它有一个删除了复制构造函数)。
更确切地说,它是使用导致错误的初始化列表初始化地图。
然而,令我惊讶的是,第二个版本,即我将无序地图的value_type
定义为FooPtr
的 const引用,确实已编译。
直到今天,我认为通常不可能在标准容器中存储引用类型的值。虽然这种行为在某种程度上是直观易懂的,但由于声明一个(const)引用会阻止 - {禁止 - 复制unique_ptr
,我仍然不完全理解这是如何工作的原因。 如果它完全有效, 当然;如果这只是一个导致未定义行为的微妙角落,我不会感到惊讶。
答案 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(副本转换为引用的对象),但是包含引用的对不是。
我怀疑图书馆的意图是允许那里的参考,但是可能缺少禁令。无论如何,我现在很困。也许有人可以找到它。