[c++] What is the copy-and-swap idiom?

I would like to add a word of warning when you are dealing with C++11-style allocator-aware containers. Swapping and assignment have subtly different semantics.

For concreteness, let us consider a container std::vector<T, A>, where A is some stateful allocator type, and we'll compare the following functions:

void fs(std::vector<T, A> & a, std::vector<T, A> & b)
{ 
    a.swap(b);
    b.clear(); // not important what you do with b
}

void fm(std::vector<T, A> & a, std::vector<T, A> & b)
{
    a = std::move(b);
}

The purpose of both functions fs and fm is to give a the state that b had initially. However, there is a hidden question: What happens if a.get_allocator() != b.get_allocator()? The answer is: It depends. Let's write AT = std::allocator_traits<A>.

  • If AT::propagate_on_container_move_assignment is std::true_type, then fm reassigns the allocator of a with the value of b.get_allocator(), otherwise it does not, and a continues to use its original allocator. In that case, the data elements need to be swapped individually, since the storage of a and b is not compatible.

  • If AT::propagate_on_container_swap is std::true_type, then fs swaps both data and allocators in the expected fashion.

  • If AT::propagate_on_container_swap is std::false_type, then we need a dynamic check.

    • If a.get_allocator() == b.get_allocator(), then the two containers use compatible storage, and swapping proceeds in the usual fashion.
    • However, if a.get_allocator() != b.get_allocator(), the program has undefined behaviour (cf. [container.requirements.general/8].

The upshot is that swapping has become a non-trivial operation in C++11 as soon as your container starts supporting stateful allocators. That's a somewhat "advanced use case", but it's not entirely unlikely, since move optimizations usually only become interesting once your class manages a resource, and memory is one of the most popular resources.

Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to copy-constructor

Disable copy constructor What is The Rule of Three? What is the copy-and-swap idiom? Clone() vs Copy constructor- which is recommended in java Dynamically allocating an array of objects

Examples related to assignment-operator

Why don't Java's +=, -=, *=, /= compound assignment operators require casting? What is The Rule of Three? What is the copy-and-swap idiom? What are the differences between "=" and "<-" assignment operators in R?

Examples related to c++-faq

What are the new features in C++17? Why should I use a pointer rather than the object itself? Why is enum class preferred over plain enum? gcc/g++: "No such file or directory" What is an undefined reference/unresolved external symbol error and how do I fix it? When is std::weak_ptr useful? What XML parser should I use in C++? What is a lambda expression in C++11? Why should C++ programmers minimize use of 'new'? Iterator invalidation rules

Examples related to copy-and-swap

What is the copy-and-swap idiom?