How can shared_ptr offer noexcept assignment? - c++

How can std::shared_ptr offer a noexcept operator=? Surely, if this shared_ptr is the last one, then it will have to destroy its contents, and it can't guarantee that the destructor of that object does not throw, or the custom deleter used originally does not throw.

Looks like a defect to me, though not one I can find in the active issues list (though #2104 is similar).
Per [C++11: 20.7.2.2.3/1], the assignment is defined to be equivalent to shared_ptr(r).swap(*this);
But per [C++11: 20.7.2.2.2], ~shared_ptr itself is not noexcept.
Unless I've misunderstood the way in which noexcept works, this must be an error.
Alternatively it could simply mean that the assignment operator is only usable when neither the underlying object type nor the deleter type throw on destruction, though even in such a scenario, the lack of any informative note in the standard wording makes me think that this is unlikely.

According to the isocpp forums, shared_ptr simply assumes that the deleter will not throw, and otherwise is UB. This would mean that the real defect is that shared_ptr's destructor is not marked as nothrow.

It's important to note that reset() (without parameters) and swap are declared nothrow as well.
Also if we take a look at boost::shared_ptr it provides the same declarations, except it also declares it's destructor as never throws which std::shared_ptr for some reason doesn't.
As far as I understand, what it means is not "I guarantee that ~T() will not throw", but "I prohibit ~T() to throw and hope you know what you are doing".

Related

Are std::list::splice() and std::forward_list::splice_after() declared as noexcept in C++11?

Cppreference mentions nothing about the exception guarantee of std::forward_list::splice_after() and std::list::splice().
However, since these 2 functions only change the pointer of the list node and thus do not need to copy/move any elements or allocate any memory, IMHO they should be noexcept.
Are they noexcept in C++11? If they are not, why not?
All but one has a "Throws: Nothing." in the standard and the one that is missing it appears to be an oversight.
They are not noexcept because they are narrow-contract. If you break the (many) preconditions, a debug-mode implementation may want to throw an exception.

Why implementing swap() as non-throwing

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.
My question is why we should implement our swap() function as a non-throwing one
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.
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.
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)
For some classes such as
a class following the pimpl idiom
we know that the implementation of swap will not need to throw because
It wouldn't make much sense for such a kind of function to throw an exception.
When it doesn't make sense to throw an exception, then it is best not to throw an exception.
There can be other classes such as those that contain complex members without a specialized swap function, but with potentially throwing copy constructor / assignment. For such classes we can not implement swap that never throws.
swaping your pImpls can't fail, in a well-formed program. (And the behaviour in an ill formed program doesn't matter). There is nothing to throw

std::unique_ptr and exception safety

Do I need to wrap std::unique_ptr usage with try/catch in code which should be exception safe?
std::unique_ptr will hold a raw memory block created by ::malloc (with my custom deleter to call ::free).
All of std::unique_ptr's constructors* are noexcept
malloc won't throw any exception on failure... it will just return nullptr.
I believe your deleter's constructors won't throw anything either.
So you don't need to catch anything, since nothing will be thrown.
*: See C++11 ยง20.7.1.2.1 unique_ptr constructors [unique.ptr.single.ctor]
As mentioned in the comments, this answer is relevant for C++14 only.
Despite the good answer from #keenyt, it's worth to say that std::make_unique<T> can throw, even though the constructors of std::unique_ptr are noexcept.
Actually, whether the above mentioned statement throws or not mostly depends on the constructors of the type T involved.
As an example from cppreference.com for std::make_unique:
May throw std::bad_alloc or any exception thrown by the constructor of T. If an exception is thrown, this function has no effect.
So, a refinement of the answer would be: no, you don't need a try/catch block, unless you are using std::make_unique and the constructors of your type T can throw.

Is there a legal way to move from gsl::not_null<T>?

The Guidelines Support Library introduced not_null<T> who's purpose is to enforce an invariant on pointer-like types, advertently on smart pointers. However it's a known issue that not_null<unique_ptr<T>> doesn't work.
As far as I see the reason is that unique_ptr<T> is not copy-constructible and not_null<T> doesn't have a constructor that would move from its T. not_null<T> is not default-constructible either because it would break it's invariant. Even if we could construct not_null<unique_ptr<T>>, it would be impossible to meaningfully reach the unique_ptr inside because we couldn't copy unique_ptr and moving it would leave not_null<T> with a nullptr. It looks like a perfect trap.
I argued that we could legally move from a not_null<T> object in a specific context: just before it goes out of scope. In other words, moving from it should be the last access before destruction. That way the object with broken invariant wouldn't be observable to the rest of the program. (It would be observable for not_null's own code only.)
In the following examples let's assume that we can move from not_null<T>.
not_null<unique_ptr<int>> f()
{
return make_unique<int>(1);
}
void g(not_null<unique_ptr<int>> p)
{
...
}
void h()
{
auto p = f();
g(make_unique<int>(2));
}
Is my assumption correct that state of the not_null<unique_ptr<int>> returned from f() couldn't leak after moving from it (just for the example)?
Is my assumption correct that state of the not_null<unique_ptr<int>> passed to g() couldn't leak after moving from it (just for the example)?
Is it possible to allow this special kind of moving while prohibiting the common case of moving in C++14/17?
1&2: Ignoring the fact that elision would render the question moot on any compiler worth using, yes. Also ignoring the fact that unique_ptr cannot "leak".
3: No.
This has been the subject of some debate on the ISO C++ proposals mailing list. The general concept is that of a "destructive move", where the act of moving from an object and destroying it are performed in the same call. But this would have to be a language feature; there is no way in C++14 to tell whether a move constructor/assignment is being called such that the given object is certainly about to be destroyed.

Can queue::pop return a value now?

I know std::queue::pop() returns void. For two reasons:
exception safety: something might throw after removing the element
to be able to return the value by reference
Fine.
Now if I understand the new C++11 move semantics correctly, the second is no longer a valid argument.
So... the only thing preventing std::queue to have a pop-like function returning the value lies in the possibility that the move constructor throws?
I have a hard time thinking of situations where such a move constructor would throw. Who knows of an example?
I guess the same goes for std::stack::pop(), std::vector::pop_front(), std::vector::pop_back(), std::deque::pop_front(), std::deque::pop_back(), std::list::pop_front(), std::list::pop_back() and what not.
There aren't many cases where std::move() can throw in the standard library but there are cases. For example, if the container uses a stateful allocator, its children also use this allocator, but it won't be moved to a result: this would rather get a default constructed version of an allocator (if I remove correctly). Given that the allocators are stateful this means that the object can't be moved and thus the move construction fails with an exception. Why does this type then have a move constructor? Well, because it might be instantiated with non-stateful allocator in which case moving won't throw. In addition, once we move to user defined classes we have no idea under which condition moving them might throw.
Using clever SFINAE techniques it would indeed be possible to have an atomic non-throwing pop_and_move() for just datatypes that implement no-throwing move or no-throwing copy.
There is even a noexcept() construct available to see if something might throw.
One of the new concepts in C++11 in particular that extends SFINAE is that if the body doesn't compile the function doesn't exist. Thus one could implement based on noexcept().
I would say for backward compatibility the function would need a new name, which therefore allows it to co-exist with the existing functionality of calling them separately, not breaking containers of types that do not have the semantics to allow it.
Another problem is, that not every class really benefits from moving, i.e., they might only have a copy ctor.
struct DontLikeMoves{
// some data, whatever...
DontLikeMoves(DontLikeMoves const& other){
// might throw, who knows!
// and this will even get called for rvalues
}
};