Why does every STL container have a swap function defined as a member function?
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.
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.
Since the free std::swap
has overloads for each container, you're right that member function swap
s aren't really necessary. The free overloads could have been declared friend
s and performed all the implementation-specific, container-specific magic to make an efficient swap.
As it is, they invoke the member swap
s. 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.
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...
上一篇: 朱莉娅在朱莉娅的语法高亮