为什么在C ++ 11(涉及分配器)中交换标准库容器会引起问题? [英] Why can swapping standard library containers be problematic in C++11 (involving allocators)?

查看:116
本文介绍了为什么在C ++ 11(涉及分配器)中交换标准库容器会引起问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意::最初由 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::valuetrue,则ab的分配器也应交换 使用对非成员swap的未经验证的调用. 否则,他们应 除非a.get_allocator() == b.get_allocator() .

If allocator_traits<allocator_type>::propagate_on_container_swap::value is true, then the allocators of a and b shall also be exchanged using an unqalified call to non-member swap. Otherwise, they shall not be swapped, and the behavior is undefined unless a.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_swapstd::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,它使用mallocoperator 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆