11

Consider the queue container in STL.

It is my understanding that swap() available in the <algorithm> header would work just fine.

I understand that swap() will only copy the queue instances superficially, that is, only the front and rear pointers will be copied, along with the size, and other data members.

The entries in the two queues would not physically swap places, but I do not see why that would be nescessary in any scenario as once the pointers and size is swapped, the two queues will effectively be swapped.

Aayush Mahajan
  • 3,856
  • 6
  • 25
  • 32
  • 3
    Typically - if some STL container has a member function, functionality of which, is also available via ``, it means that STL container, knowing the structure of data, may perform said functionality faster, that the generic `` one. – Algirdas Preidžius Mar 10 '17 at 12:26

3 Answers3

4

Before C++11 introduced move semantics, the generic implementation of std::swap had no choice but to do two copies. Conceptually, this:

template <class T>
void swap(T &a, T &b)
{
  T t(a);
  a = b;
  b = t;
}

Notice that this generic std::swap doesn't know anything about internals of the object passed in (because it can be called with an arbitrary user type, for example), and thus has to do copies. Note that for containers, this means copying the elements.

Providing an optimised member function swap which just re-points some internal pointers is therefore a huge performance win.

Since move semantics were introduced, the generic swap can be made more efficient using moves. Again, conceptually:

template <class T>
void swap(T &a, T &b)
{
  T t(::std::move(a));
  a = ::std::move(b);
  b = ::std::move(t);
}

Of course, in practice, it probably has requirements about the move operations involved being non-throwing, and all sorts of extra bits.

With move semantics in place, the optimised member versions are perhaps less important than they were before. But it's still possible that with knowledge of the exact implementation details of a type, swapping it can be faster than three generic moves.


In addition to the discussion above, notice that type-specific overloads of std::swap exist for almost all types defined in the standard library. What these overloads do is simply call the optimised swap member function on one of the operands. That way, you have the best of both worlds: a generic free function swap which can be called with anything, but which has optimised implementations for everything the standard library is aware of.

It would be possible to forego the member functions and provide the optimised implementations inside the std::swap overloads directly, but this would mean they'd likely need to be friended and could be perceived as worse accessible to user code.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
3

Since the free std::swap has overloads for each container, you're right that member function swaps aren't really necessary. The free overloads could have been declared friends and performed all the implementation-specific, container-specific magic to make an efficient swap.

As it is, they invoke the member swaps. I suppose this allows for additional flexibility in how to call those functions, and it saves lots of friend declaration.

I'm not aware that there's anything more to it than that.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

When the uniform call syntax proposal (2014 version by Bjarne Stroustrup) is finally adopted, after some final tweaking, your question will become moot in the sense that std::swap(my_queue, another_queue) and my_queue.swap(other_queue) will likely be aliases of the the exact same function. Unfortunately, that won't happen for C++17. Maybe in C++20? One can dream...

einpoklum
  • 118,144
  • 57
  • 340
  • 684