C++ the good parts — std::swap

2021 Aug Update

Clarifications added, ommissions and typos fixed. Importantly Godbolt implementation was added.

Caveat Emptor: this is one long post. It covers a lot. And for C++ newcomers it is full of unavoidable subjects. Please read and re-read. And most importantly ask questions in comments. And please do suggest improvements.

std::swap is quite fundamental. And allow me to assume, fundamentally glanced over by you :) This is a pity; understanding std::swap concepts fully will make you more clear on a few other important C++ concepts.

Advice: to understand C++ swap one must be having a firm grasp of the other C++ fundamentals fully. Please, if in doubt, stop reading and jump to the link provided in the text in bold font, for a quick refresh and then jump back.

The easy start

Two easy things to “tickle your fancy” before we dive in.

Canonical swap implementation for your class

Here is how you provide your own swap for your class/struct :

And this is how it will be called/used:

If not sure what it is, look up the ADL now. Now let us proceed.

Swap is not Exchange

Exchange of values is the other fundamental and distinctive operation.  The programing language you code in must allow you to clearly separate the fundamental operations.  Swap and  Exchange are two fundamental operations. Not one. The key difference between swap and exchange is the lifetime of values swapped or exchanged.

Note: here in this text we would use the word “exchange” as normal people do. In case you know or do not want to know about std::exchange please see here.

Most importantly: B is said to be moved from after the std::swap is done.

(hint: yup, here is that link to the refresher, in bold ). So… Why do we talk “move” when this text is about “swap”?

Let’s Move Forward

The move is a fundamental conceptual building block in C++. The synopsis std::swap is:

That is a generic function. The use of std::move assures it is implemented and executed and second, values are moved for all the types involved for arguments a and b above. Let us emphasize: Moved. Not assigned and not exchanged.

The swap concept is using the move concept. Move concept is the fundamental building block to value semantics of modern C++.  The move is fundamental in making value semantics feasible. “move constructor” and “move assignment”; two more fundamental concepts.

To understand and use for your own benefit the moving and swapping in C++ please always be aware of what type category, exactly is being moved or swapped. We will explain and focus on the differences regarding the types of values moved or swapped.

Here we will peruse three particular categories of types to form the facets of the C++ moving/swapping. A bit unlike the standard, we will name them into three groups, just for this post:

  1. Fundamental Types

  2. User-Defined Trivial Types

  3. User-Defined Non-Trivial Types

These names are somewhat non-existent in C++ standard documents but are true and easy for you to understand right now. There is a bit more to this whole subject. I might suggest you start from here:  type system. Before proceeding please be sure you are clear on the C++ types.

Swapping fundamental types

This type category is here as a natural and good starting point on the std::swap journey of discovery.  There is nothing surprising about swapping fundamental types.

The most important thing to notice here:  B is moved from. C++ standard does mention that explicitly: B is in the “undefined state” after the move of its value to A.  Remember: Swap is not Exchange.

You obviously can see it, B is actually alive and well, and equals 2, as you have expected. But keep in mind C++ is a language based on abstract thinking and abstractions. Thus the swap definition is carefully made so it applies to all the types of A and B above.  Above just happens to be two integers. But please always have this mental picture

That is actually standardized.  It is very precisely defined what you can swap and what you can not swap.   Any type T can be swapped as long as it is Swappable , which in code can be (and it is) checked with std::is_swappable and friends.

And crucially there is always one left in the “undefined state” because it was “moved from” inside a swap operation. Now onto the next group of types.

User-Defined Trivial Types

(please go to the next page)