Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Channels ▼

Andrew Koenig

Dr. Dobb's Bloggers

Object Swapping, Part 7: How Do You Call It?

April 25, 2012

We've talked about why swapping is important, and about how to use it to implement other operations such as assignment. We shall now look more closely at how to use it.

More Insights

White Papers

More >>


More >>


More >>

Suppose we define a class X, and we write our own swap operation for it:

class X { /* code */ };
void swap(X& x, X& y) { /* more code */ }

If we have two variables of class X, and we want to swap them, we can call our swap function:

void foo() {
     X x1, x2;
            // …
            swap(x1, x2);
     // and so on

If instead of calling swap(x1, x2), we mistakenly call std::swap(x1, x2), our program will seem to work — so long as our class X supports copying (or moving) and assignment. The reason is that std::swap looks something like this:

     template<class T> void swap(T& t1, T& t2) {
           T temp = t1;   
           t1 = t2;
           t2 = temp;

When we call std::swap(x1, x2), we are saying that we want to use swap from the standard library rather than the one that we defined along with our class. Fortunately or unfortunately, depending on your point of view, the standard-library version is capable of swapping most classes — but we can expect that it will probably do so more slowly than a class-specific swap operation.

So it's not a good idea to call std::swap explicitly, because doing so rules out the possibility of using a class-specific version. On the other hand, consider this example:

void bar() {
     int i = 0, j = 0;
            // …
           swap(i, j);  // Danger!
     // and so on

We have changed the names of our function and its variables, and changed the variables' type from X to int. Now, we have no assurance that this program will compile. The reason is that in order to swap integers, we must use std::swap; and we do not know whether std::swap was ever imported into the global namespace. If we want to be sure that this code will work, we had better write it this way:

void bar() {
     int i = 0, j = 0;
            // …
            std::swap(i, j);  // Much better.
     // and so on

This is an unfortunate situation, because it implies that in order to swap two variables, we have to know their types. Requiring such knowledge makes generic programming much more difficult.

Fortunately, there is a way out of this dilemma:

void bar() {
     using std::swap;
     int i = 0, j = 0;
            // …
            swap(i, j);  // Best of all.
     // and so on

On the surface, this code looks like it should not work. After all, it imports std::swap into the scope of bar, so when we call swap(i, j), one would think that it would find only std::swap. However, the code does work — because of a C++ feature called argument-dependent lookup (abbreviated as ADL). ADL says that when you call a function without using :: as part of its name, then in addition to the normal scope lookup, the compiler looks for the function name in every namespace that contains the definition of the call's argument types.

In other words, when we call swap(x, y), and x and y are objects of class X, the compiler finds the namespace that contains the definition of class X — here, the global namespace — and looks there for the definition of swap in addition to looking in the normal places.

In fact, ADL allows this technique for calling swap to work even if we define our class in a namespace of its own:

             namespace Mine {
                  class X { /* code */ };
          void swap(X& x, X& y) { /* more code */ }
     void baz() {
           using std::swap;
           int i = 1, j = 2;
           Mine::X x1, x2;
                           // …
swap(i, j);
swap(x1, x2);
           // and so on

In this example, the call to swap(i, j) will find std::swap, because that is the only definition of swap directly available within the scope of baz. Moreover, the call to swap(i, j) will find Mine::X::swap because of ADL. Even though swap is not defined in the global namespace at all in this example, overloading will find the correct version for each call. ,p>When you swap variables, and you don't want to have to know their types when you're writing your code, this technique is worth remembering.

Related Reading

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.



Yes, Andrew Koenig is modest, he proposed this lookup method according to wikipedia



Your approach won't work if "X" is a template class. In order to specialize std::swap for a class template, you'd need partial specialization. This is not supported in C++. You can use overloading, but, while it is legal to specialize a function in the std::namespace (for a user-defined type) it isn't legal to overload a function in std.

There is an alternative approach which Andrew didn't mention. You can use boost::swap, which effectively does "using std::swap: swap(...);" for you.

By the way, Andrew is being modest when he refers to argument-dependent lookup as ADL. In the standard it has another name. It is called "Koenig Lookup."


Isn't it more prudent to stick to using std::swap only and specialize it explicitly for the case of class X?