我想知道,std::vector::insert
的异常安全保障究竟是什么?我对这个函数的单参数和范围重载感兴趣。
答案 0 :(得分:2)
确切的保证在C ++ 11 23.3.6.5中给出:
如果除了复制构造函数之外抛出异常,移动构造函数,赋值运算符或移动赋值运算符
T
或任何InputIterator
运算都没有效果。如果非CopyInsertable
T
的移动构造函数抛出异常,则效果未指定。
答案 1 :(得分:2)
通常,insert
的单元素形式对[container.requirements.general] / 10的任何容器都有强烈的异常保证,但vector::insert
是此规则的例外:< / p>
[vector.modifiers] / 1适用于vector::insert
; InputIterator
此处指的是插入范围的insert
的重载。
如果除了复制构造函数之外抛出异常,移动构造函数,赋值运算符或移动赋值运算符
T
或任何InputIterator
运算都没有效果。如果非CopyInsertable
T
的move-constructor抛出异常,则效果未指定。
vector
是一个支持分配器的容器,这意味着它使用分配器进行内存分配和构造其元素[container.requirements.general] / 3
对于受本子条款影响的声明
allocator_type
的组件,存储在这些组件中的对象应使用allocator_traits<allocator_type>::construct
函数构造,并使用allocator_traits<allocator_type>::destroy
函数销毁。这些函数仅针对容器的元素类型调用,而不是针对容器使用的内部类型调用。
我认为这意味着可以在不使用分配器的情况下创建不是容器元素的本地对象(例如,用于复制和交换)。否则,对价值类型的ctors的要求将毫无意义;分配器的construct
函数可能具有与值类型的ctor不同的异常保证。
CopyInsertable
在[container.requirements.general] / 13中指定,要求
allocator_traits<A>::construct(m, p, v);
结构良好;其中A
是分配器类型,m
的类型为A
,p
是指向T
的指针,v
是类型的表达式(const
)T
,T
是容器的值类型。这是一个来自一个参数(复制或移动构造)的现场构造。
同样,MoveConstructible
已指定,但v
(始终)是T
类型的右值。对于零个或多个参数,EmplaceConstructible
遵循相同的形式,而不是v
。
序列容器的insert
函数对其各种形式的值类型强加了不同的要求[sequence.reqmts];这里包括vector
的其他要求:
const
)T
的左值,对于表单插入N个副本,T
应为{{ 1}}和CopyInsertable
CopyAssignable
类型的右值的单个参数,T
应为T
和MoveInsertable
MoveAssignable
应来自解除引用的迭代器(*); T
;另外,如果范围的迭代器不是前向迭代器,则EmplaceConstructible
和MoveInsertable
(*)注意:如果必须为插入调整容器大小,那么仅来自解除引用的迭代器的MoveAssignable
是不够的(例如,EmplaceConstructible
这样的迭代器不是值类型)。规范可能要求范围形式继承单元素形式的要求,即*i
或MoveAssignable
。
旁注: CopyAssignable
的范围形式要求两个迭代器不指向要插入它们的容器。
我将异常规范解释如下:
insert
的异常规范中关于CopyInsertable
的附加声明可能区分基本保证和不保证:容器的dtor通常需要调用所有元素的dtor并释放所有元素内存(在一般容器要求中)。也就是说,除非行为未指定/未定义,否则基本保证将成立。
为什么需要将vector::insert
和move-ctor(而不是CopyInsertable
与rvalue相结合),我不知道。 move-ctor仅直接用于不是容器元素的对象(间接可能通过allocator::construct
)。
关于“无效果”( - &gt;强保证)的其他评论不应用于分配器操作(allocator::construct
)。分配器操作显然不一定是noexcept。由于您可以提供不使用值类型的construct
的copy-和move-ctor的非默认分配器,construct
必须提供强大的异常保证,即使insert
也是如此分配器操作。例如,如果分配器的construct
不是noexcept,则在调整大小期间,元素不能移动构造,但必须复制。
对于强保证,移动和复制分配必须是不可用的,因为可能需要为construct
移动元素;由于算法中创建的本地对象,copy-和move-ctor可能需要不受强保证。
答案 2 :(得分:1)