Allocator Aware Container和propagate_on_container_swap

时间:2015-02-03 21:55:45

标签: c++ c++11

std::allocator_traits模板定义了一些常量,比如propagate_on_container_copy/move_assign,让其他容器知道在复制或移动操作期间是否应该复制第二个容器的分配器。

我们还有propagate_on_container_swap,它指定在交换操作期间是否应该复制分配器。

Allocator Aware容器是否真的需要检查allocator_traits<A>::propagate_on_container_swap中的Container::swap()?通常,我按如下方式实现swap:

Container::swap(Container& other)
{
   Container tmp(std::move(other));
   other = std::move(*this);
   *this = std::move(tmp);
}

换句话说,我只是根据移动分配实现交换。由于移动赋值操作已经必须处理分配器感知(通过检查propagate_on_container_move_assign),是否可以像这样实现Container::swap(),而不是编写一个完全不同的swap函数,它明确地检查对于propagate_on_container_swap

2 个答案:

答案 0 :(得分:6)

重要的是要区分标准对代码的要求与它对std :: lib的实现者提供的类型的要求之间的区别。

容器需求指定std :: containers必须如何表现。但是,您可以随意编写容器。除非你将容器输入到需要std :: container行为的std :: code中,否则你很高兴。只有几个这样的地方。例如,如果您使用Container调整std::stack,那么如果您希望std::stack按照标准行事,则必须提供标准行为。

回到你的问题,如果你希望你的Container在这方面与std :: container之一具有相同的行为,那么你将需要检查并遵守 all propagate_on traits,以及所有其他分配器要求。这是一项非常重要的任务。我不一定推荐它。

std :: containers将不会执行容器移动构造,也不会在swap期间移动分配。他们将交换他们的内部表示。他们将根据propagate_on_container_swap决定(在编译时)他们是否会交换分配器。

如果propagate_on_container_swap为真,它们将交换分配器和内部表示。同样在这种情况下,swap将在C ++ 1z中noexcept(我们希望这是C ++ 17)并转发。

如果propagate_on_container_swap为false,则不应交换分配器,甚至不需要Swappable。但是容器内部仍然是交换的。在这种情况下,如果两个分配器不比较相等,则行为未定义。

如果保持Container::swap不变,并根据std::stack创建Container,则std::stack::swap将不会有标准行为。但是,它将具有您的Container::swap的行为,如果对于所述std::stack的客户端以及他们可能使用的任何分配器都没有问题,那么就不会造成任何伤害。 std::stack::swap不会以神秘的方式表现,因为你并没有严格遵守std :: containers所需的分配器的所有复杂细节。

答案 1 :(得分:0)

当然,您可以使用move-ctor和容器的移动分配来实现它 这就是std::swap这样做的方式,并且没有理由重新编写它而不是使用标准的。

那些传播常数允许省略无用的额外工作,你可以自由地忽略优化的可能性。
请注意,您可能做了太多工作,即swap可能效率低下。