- STL 容器元素是否需要具有
noexcept
复制构造函数和复制赋值运算符?如果可能,请提供参考。 - 如果不是,当在多插入期间发生异常时,STL 容器的状态是什么,例如在填充插入期间。
尝试编写允许拦截/否决修改的通用包装器时会出现问题。我能想到的任何实现都可能会改变底层容器的语义,除非专门针对每种容器类型(这不是一个真正的选择)。
例如,std::vector
有一个填充插入:
void insert (iterator position, size_type n, const value_type& val);
这需要value_type
同时是CopyInsertable和CopyAssignable。请注意,它不需要值类型为DefaultConstructible。
编辑 3 Stroustrup本人(第 956 页上的表格)表示多元素插入应该对所有向量、双端队列、列表和映射都有强有力的保证。这意味着完整的标准库操作会自动成功或失败。
编辑 4但是,该保证仅适用于相关操作(在本例中为复制构造函数)本身不引发异常的情况,这正是我的问题。
据我了解,这留下了两种基本的实现方法:
- 为新元素创建虚拟
val
条目并复制分配。这仅在可以通过复制容器中的现有元素或DefaultConstructible(这不是必需的)value_type
来创建虚拟元素时才有效。 - 一个接一个地复制构造元素到容器中它们各自的位置。这似乎或多或少是规范的实现。
编辑 2:我不会将此称为未定义行为,因为该术语似乎使人们认为未定义为由语言运行时/标准定义。
当复制构造函数或复制赋值运算符引发异常时,这两种实现似乎都会使容器留下未知内容(即不清楚容器在异常之后包含哪些元素)。
编辑 1:请注意,这并不意味着我认为 C++ 运行时存在不良行为,例如内存泄漏或未定义的值。但是,似乎或多或少没有说明容器的内容是什么。特别是,容器的内容可能已经完全(尽管始终如一地)改变。
例如,考虑第三种(混合)方法:
- 创建
n
模板对象的副本列表val
。 - 将此列表中的元素复制分配到目标容器中。
不同之处在于复制构造函数引发异常时对容器的影响。在这种情况下,如果复制构造函数抛出,容器的内容将保持不变(但当复制赋值运算符抛出时仍会导致未指定的内容)。使用指针时(即不使用时std::vector
),复制赋值可能会被忽略,只有指针重新排列,从而使操作原子化。例外。
至于noexcept
容器元素:对象是通过创建的allocator_traits<value_type>::construct(ptr, args)
,这不是noexcept
,我也找不到容器元素大多数具有noexcept
复制构造函数/复制分配运算符的要求(例如std::shared_ptr
,std::unique_ptr
需要这个)。
请注意,复制构造和复制分配的自动生成操作必须是noexcept
,除非它们需要调用本身可能引发异常的操作。
这让我感到困惑,我确定我错过了一些东西,但我无法弄清楚标准中可能证明我错了的部分。