Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why implementing swap() as non-throwing

Tags:

c++

c++03

I do understand why sometimes it is recommended to implement our own swap() function for a given class.

For instance, if we have a class following the pimpl idiom we would likely want to define our own copy constructor, so that it performs a deep copy of the contents of the object passed as an argument instead of the shallow copy that would be performed by the default copy constructor. The same could apply to the copy assignment operator.

Since it seems that std::swap() is implemented in terms of (at least, when it comes to C++03) both the copy constructor and the copy assignment operator. It would be inefficient to perform deep copies of the objects to be swapped, since just a swap of the pointers contained by these objects need to be done.

My question is why we should implement our swap() function as a non-throwing one.

In the case explained above, I assume it is just about semantics: since no new resources are being allocated (i.e.: two existing pointers are just being swapped). It wouldn't make much sense for such a kind of function to throw an exception.

However, there may be other reasons or scenarios I am overlooking in this reasoning.

like image 700
ネロク・ゴ Avatar asked Aug 18 '26 05:08

ネロク・ゴ


2 Answers

My question is why we should implement our swap() function as a non-throwing one

  1. Because swap is completely useless if it might throw.

    Consider: you swap two instances, and the operation throws. Now, what state are they in?

    The strong guarantee is that there are no side-effects if an exception was thrown, meaning both original objects are left in their original state.

    If we can't meet the strong guarantee, we simply can't use swap in many cases, because there's no way to recover usefully from a failure, and there's no point in writing that version of swap at all.

  2. Because there's no reason for it to throw.

    The trivial implementation of swap (now) uses move-assignment and -construction.

    There's generally no reason for a move-constructor to throw: it doesn't allocate anything new, it's just re-seating existing data. There's generally no reason for move-assignment to throw (as above), and destructors should never throw - and those are the only operations required.

like image 77
Useless Avatar answered Aug 21 '26 00:08

Useless


EDIT

I've originally understood the question as "why would you use the throw specifier on the swap function. This answer might be off topic since I doesn't explain why would swap never throw.


I think the best answer is why not ?.

Why would you not specify that a function will never throw when this function as no reason to throw ?

You should always implement function as non-throwing when they have no reason to throw exception: you offer stronger guaranty for your function.

Furthermore, with some meta programming, you can take advantages of functions being non-throwing. Some STL classes use that to have faster member function when the swap/copy/move(C++11) is no-throw. (Actually I'm not sure that they take advantage of a function being no-throw in pre-C++11 code)

like image 29
nefas Avatar answered Aug 21 '26 00:08

nefas