注意: GreenScape最初要求comment。
在阅读Why are the swap member functions in STL containers not declared noexcept?之后,似乎在为标准容器执行a.swap(b)
时潜在的未定义行为的原因归结为也交换或不交换底层分配器。
答案 0 :(得分:13)
通过挖掘标准(N3797)来开始:
23.2.1p9
一般容器要求[container.requirements.general]
如果
allocator_traits<allocator_type>::propagate_on_container_swap::value
是true
,然后还应交换a
和b
的分配器 使用对非成员swap
的未命名调用。 否则,他们应该 不得交换,除非a.get_allocator() == b.get_allocator()
,否则行为未定义。
propagate_on_container_swap
的目的是什么?
如果分配器有一个名为propagate_on_container_swap
的 typedef ,它引用了std::true_type
两个容器的基础分配器,那么它们也会交换。 [1] < / SUP>
如果propagate_on_container_swap
为std::false_type
,则只会交换两个容器的数据,但分配器将保留在原位。
[1] 这意味着在a.swap(b)
之后,a.get_allocator()
将是之前的b.get_allocator()
;分配器已交换。
有状态分配器的含义是什么?
Allocator不仅负责为标准容器中的元素分配内存,它们还负责释放所述元素。
C ++ 03并不允许在标准容器中使用有状态分配器,但是C ++ 11要求必须支持这样的容器。这意味着我们可以定义一个分配器,它取决于它的构造方式,以某种方式起作用。
如果分配器的propagate_on_container_swap::value
等于false
,则所涉及的两个分配器之间的状态差异可能会导致未定义的行为,因为分配器的一个实例可能不是与另一方处理的数据兼容。
有状态分配器如果没有正确交换可能会出现什么问题?
我们假设我们有MagicAllocator
使用malloc
或operator new
来分配内存,具体取决于它的构建方式。
如果它使用malloc
分配内存,则必须使用free
取消分配内存,如果operator new
,则需要delete
;因此,它必须保留一些信息,说明它应该使用哪两个。
如果我们有两个std::vector
,它们都使用MagicAllocator
但具有不同的状态(意味着一个使用malloc
而另一个operator new
),并且我们不会使用a.swap(b)
。 t在free
之后交换分配器,分配器在交换后不会匹配为两个向量中的元素分配的内存 - 这意味着错误的delete
/ {{1}}可能会被要求解除分配。