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

How did I manage to store a reference type in a standard container?

本文关键字:存储 引用类型 标准      更新时间:2023-10-16

在尝试使用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(它有一个删除的复制构造函数)。

更准确地说,是使用初始化列表对map进行初始化导致了错误。

然而,令我非常惊讶的是,我将无序映射的value_type定义为FooPtrconst引用的第二个版本确实编译了。 直到今天,我一直认为在标准容器中存储引用类型的值是不可能的。虽然这种行为在某种程度上是可以直观理解的,因为声明(const)引用可以防止(否则是禁止的)复制unique_ptr,但我仍然不完全理解这是如何工作的,或者为什么这样做。如果它能工作,当然;如果这只是一个微妙的角落情况,导致未定义的行为,我不会感到惊讶。

您违反了库的约束。这将导致未定义的行为。库可能会也可能不会检测到它是引用。

引用的问题在于标准库允许假定容器拥有保存元素值的对象,因此可以调用其析构函数,特别是它可以这样做:
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的(副本转移到被引用的对象),但包含引用的pair不是。

我怀疑库的意图是允许在那里引用,但是可能缺少禁止。不管怎样,我现在很困。也许有人能找到。