The std::allocator_traits
template defines a few constants, like propagate_on_container_copy/move_assign
to let other containers know whether they should copy the allocator of a second container during a copy or move operation.
We also have propagate_on_container_swap
, which specifies whether the allocator should be copied during a swap operation.
Is it really necessary for an Allocator Aware container to check for allocator_traits<A>::propagate_on_container_swap
in Container::swap()
? Usually, I implement swap as follows:
Container::swap(Container& other)
{
Container tmp(std::move(other));
other = std::move(*this);
*this = std::move(tmp);
}
In other words, I simply implement swap in terms of move assignment. Since the move assignment operation already has to deal with allocator awareness (by checking propagate_on_container_move_assign
), is it okay to implement Container::swap()
like this, instead of writing a totally different swap
function which explicitly checks for propagate_on_container_swap
?
It is important to draw a distinction between requirements the standard places on your code vs the requirements it places on types provided by the implementor of the std::lib.
The container requirements specify how the std::containers must behave. However you are free to write your container however you like. Unless you input your container into std::code which requires the std::container behavior, you are good to go. There are just a couple of such places. For example if you adapt your Container
with std::stack
, then you will have to provide standard behavior if you expect the std::stack
to behave according to the standard.
Getting back to your question, if you desire your Container
to have the same behavior as one of the std::containers in this regard, then you will have to check and abide by all of the propagate_on
traits, and all of the other allocator requirements. This is a non-trivial task. And I am not necessarily recommending it.
The std::containers will not perform a container move construction nor move assignment during swap
. They will instead swap their internal representations. They will decide (at compile-time) based on propagate_on_container_swap
whether or not they will swap allocators.
If propagate_on_container_swap
is true, they will swap allocators and internal representations. Also in this case, swap
will be noexcept
in C++1z (we hope that is C++17) and forward.
If propagate_on_container_swap
is false the allocators shall not be swapped, and need not even be Swappable
. However the container internals are still swapped. In this case, if the two allocators do not compare equal, the behavior is undefined.
If you keep your Container::swap
as it is, and create a std::stack
based on your Container
, the std::stack::swap
will not have standard behavior. However, it will have the behavior of your Container::swap
, and if that is fine with the client of said std::stack
and whatever allocator they may be using, then no harm done. std::stack::swap
will not behave in mysterious ways just because you didn't rigorously follow all of the intricate details for allocators that the std::containers are required to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With