为什么在C ++ 11(涉及分配器)中交换标准库容器会引起问题? [英] Why can swapping standard library containers be problematic in C++11 (involving allocators)?
问题描述
注意::最初由 GreenScape 要求为
Note: Originially asked by GreenScape as comment.
在阅读为什么STL容器中的swap成员函数没有被声明为noexcept之外?看来,潜在的原因对标准容器执行a.swap(b)
时的未定义行为归结为也交换或不交换基础分配器.
After reading Why are the swap member functions in STL containers not declared noexcept? it seems that the reason for potential undefined behavior when doing a.swap(b)
for standard containers boils down to also swapping, or not swapping, the underlying allocators.
- 为什么交换分配器和数据有问题?
推荐答案
让我们从深入研究标准(N3797 ):
Let's start of by digging into the Standard (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()
.
If
allocator_traits<allocator_type>::propagate_on_container_swap::value
istrue
, then the allocators ofa
andb
shall also be exchanged using an unqalified call to non-memberswap
. Otherwise, they shall not be swapped, and the behavior is undefined unlessa.get_allocator() == b.get_allocator()
.
propagate_on_container_swap
的目的是什么?
What is the purpose of propagate_on_container_swap
?
如果一个分配器具有一个名为propagate_on_container_swap
的 typedef ,它引用std::true_type
被交换的两个容器的基础分配器,也将交换. [1]
If an Allocator has a typedef named propagate_on_container_swap
that refers to std::true_type
the underlying Allocators of two containers being swapped, will also swap.[1]
如果propagate_on_container_swap
为std::false_type
,则只有两个容器的数据将交换,但分配器将保留在其位置.
If propagate_on_container_swap
is std::false_type
only the data of the two containers will swap, but the allocators will remain in their place.
[1] 这意味着在a.swap(b)
之后,a.get_allocator()
将是以前的b.get_allocator()
;分配器已交换.
[1] This means that after a.swap(b)
, a.get_allocator()
will be that which was previously b.get_allocator()
; the allocators has swapped.
有状态分配者的含义是什么?
分配器不仅负责为标准容器中的元素分配内存,还负责所述元素的释放.
The Allocator is not only responsible for allocating memory for the elements within a Standard container, they are also responsible for the deallocation of said elements.
C ++ 03不允许在标准容器中使用有状态分配器,但是必须存在支持这种情况的C ++ 11要求.这意味着我们可以定义一个分配器,该分配器根据其构造方式以某种方式起作用.
C++03 didn't allow stateful allocators within standard containers, but C++11 mandates that support for such must be present. This means that we could define an allocator that, depending on how it's constructed, acts in a certain way.
如果分配器的propagate_on_container_swap::value
等于false
,则所涉及的两个分配器之间的状态差异可能导致未定义的行为,因为分配器的一个实例可能与数据不兼容由其他人处理.
If the allocator has propagate_on_container_swap::value
equal to false
the difference in state between the two allocators involved might lead to undefined behavior, since one instance of the Allocator might not be compatible with the data handled by the other.
有状态分配器如果交换不正确,可能会出现什么问题?
假设我们有一个MagicAllocator
,它使用malloc
或operator new
来分配内存,具体取决于其构造方式.
Let's say we have a MagicAllocator
which either uses malloc
or operator new
to allocate memory, depending on how it's constructed.
如果使用malloc
分配内存,则必须使用free
进行分配,如果使用operator new
,则需要delete
.因此,它必须维护一些信息,说明应该使用两者中的哪一个.
If it uses malloc
to allocate memory it must use free
to deallocate it, and in case of operator new
, delete
is required; because of this it must maintain some information saying which of the two it should use.
如果我们有两个std::vector
都使用MagicAllocator
但状态不同(这意味着一个使用malloc
而另一个使用operator new
),并且我们不会在分配器a.swap(b)
上交换分配器交换后将不匹配为两个向量中的元素分配的内存-换而言之,这意味着在释放时可能会调用错误的free
/delete
.
If we have two std::vector
which both uses MagicAllocator
but with different states (meaning that one uses malloc
and the other operator new
), and we don't swap the allocators upon a.swap(b)
the allocator won't match the memory allocated for the elements in the two vectors after the swap - which in terms means that the wrong free
/delete
might be called upon deallocation.
这篇关于为什么在C ++ 11(涉及分配器)中交换标准库容器会引起问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!