Very straight forward question:
What is the reason of requirement that assignment operator must not throw exception?
In same time, the constructor can throw?
If you must not throw exception, how one might handle well known "custom" string example if there is not enough memory for buffer allocation?
If you just allocate less or keep old state, but do not throw exception, everything will "look" smooth, but there will be serious (hidden) error.
There is absolutely no such requirement. It is perfectly OK for an assignment to throw. In many cases throwing is unavoidable (e.g. when assignment must allocate some memory and there's none left).
What assignment should never do is leave an object in an undefined state. It must either successfully assign a new value, or leave the object in its original state (or perhaps some other valid state, which is less desirable) and throw.
This semantic is often implemented by the copy-and-swap idiom. The copy stage can throw. This leaves the assignee intact. The swap stage must never throw.
Related
Apparently, std::move_if_noexcept() will call the move constructor, even if it is not marked as noexcept if there is no copy constructor available.
From cpprefeerence.com (emphasis mine):
Notes
This is used, for example, by std::vector::resize, which may have to allocate new storage and then move or copy elements from old storage to new storage. If an exception occurs during this operation, std::vector::resize undoes everything it did to this point, which is only possible if std::move_if_noexcept was used to decide whether to use move construction or copy construction. (unless copy constructor is not available, in which case move constructor is used either way and the strong exception guarantee may be waived)
As std::vector is using this function on reallocation, that could leave the vector and possibly the application in an undetermined state. So, why would this be allowed?
Let's say you're doing what vector is doing when it would use move_if_noexcept. That is, you have some object obj, and you need to construct a new value of that type from obj. And after that, you're going to delete obj. That's a prime case for moving the object, so vector does that where possible.
If movement is noexcept, then moving obj is exception safe by definition. If it isn't noexcept, then you need to ask: what happens if the move constructor throws? What is the state of obj in that case? The answer is... you don't know. Even worse, what about the state from any objects you already moved from successfully? Can you move them back?
When it comes to copy constructors however, you do know. A copy constructor takes a const& to the source object. So by definition, a failed copy operation cannot modify obj (and yes, we know you can const_cast, but that makes your copy constructor a lie. Lies like that are why auto_ptr doesn't exist anymore, and I would guess that there's a blanket prohibition in the standard on lying copy constructors). So on a failed copy, obj is in its original state.
Therefore, if movement can throw, copying is preferred, as this provides the strong exception guarantee: in the event of an exception, everything goes back to the way it was.
However, if your only option is a throwing move, then you have two choices: make it so that such a type cannot ever be used with vector, or offer whatever exception guarantee the type itself offers on movement failure. And the latter is what is chosen.
It's allowed because that's what you asked for. Your choice of type doesn't allow for the strong exception guarantee, so it cannot be provided. But you can still make a vector of such types; you just need to deal with the possibility of non-copyable movement failure.
And since you're the kind of person who uses types that cannot provide a strong exception guarantee, you clearly must know how to handle these scenarios, right?
While explaining move operations on objects with a colleague, I basically said that move operations should not throw exceptions in a container because if the move operation fails, then there is no way to bring back the original object reliably. Thinking about this more, I'm wondering if that is not correct and that if a move operation that does throw, it could revert the original object back to it's original state.
The reason for this, is that if an object can throw, then it would throw not due to copying or moving the contained objects from the old to the new address, but throw if a resource failed to be acquired. So all of the original information should still be there. If this is the case, then should the compiler not be able to reverse the operations that it did to reconstitute the original object?
It could be possible for an operation to be one way, like moving an integer, but in that case it could just terminate the application, and perhaps if the developer wanted to avoid the one way operation could use a swap method instead.
This would only be possible on default move operators, as if there are any additional logic, it may be difficult for the compiler to do a reverse partial transform.
Am I oversimplifying things? Is there something that I missed which keeps containers from moving objects without a non-throwing move constructor/operator?
You can use types with throwing moves in containers like vector which can move their elements. However, such containers will not use throwing move operations.
Let's say you have a vector of 10 throwing move elements. And the vector needs to resize itself. So it moves 5 objects to the new memory, but the 6th throws. Well, that's OK; construction failed, so the assumption is that the value of the 6th object is fine. That is, whatever that type's exception guarantee is will be how things work.
But then, because the movement of one object failed, vector needs to move the last 5 objects back to the first array, since vector is trying to provide a strong exception guarantee. That's a problem, since the move back can itself fail.
C++ in general does not have valid answers when the process of repairing a failure itself fails. You can see that in exceptions; you can't emit an exception from a destructor that is called during the process of unwinding due to an exception failure. std::terminate happens in this case.
The same goes for vector. If the move back were to fail, vector has no sane answer. As such, if vector cannot guarantee that restoring its previous array state is noexcept, then it will use copying, since that can provide that guarantee.
First of all, I can hardly imagine object that acquires resources in the move operation. Think about it - unique_ptr just passes the pointer without acquiring anything, same for shared_ptr. string, vector, all the containters etc. just steal the pointers to the resources acquired earlier in default or copy constructor. I feel like throwing from move constructor is like throwing from destructor. Sure, go ahead, shoot yourself in your knee. But ok, I can accept that exceptions from this exist.
So let's move to the second point - when moving there can be a moment when actually both objects (moved from and moved to) are invalid. And to roll back from such situation would require additional 'magic' function to be called to fix one of them. So it seems the data cannot be repaired as standard does not define such a function.
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
The inherent value of a copy-swap pattern for the operator = in a C++ data container is said to arise from
Code reuse and
Exception safety.
However the copy-swap idiom allocates much more memory than would otherwise be necessary, as data is not destroyed before the copy is created, increasing the chance of exceptions substantially. Given that this is the case, what is the point in claiming that it is a useful pattern?
Are there any other cases in which a copy operation could throw (that do not relate to the objects being copied) other than running out of memory?
The copy&swap idiom for the assignment operator yields the strong exception guarantee: the original value is untouched when building a new object would throw. When reusing memory allocated for the assigned to object the strong exception guarantee can typically only be achieved when none of the involved operation may throw. Especially when class templates are involved (as in std::vector<T>) there is generally no guarantee that none of the operations throws (of course, std::vector<T> only provides the basic exception guarantee upon assignment).
In general, copy assignments can throw for whatever reason. Most likely they shouldn't throw for other reasons than failures to allocate resources but there isn't anything in the CopyAssignable concept which prohibits the operation from throwing.
I found it quite common that copy assignments were not correctly implemented and would, e.g., violate the basic exception guarantee. The indicator that this is the case is when the assignment operator needs to check for self-assignment: if a self-assignment is actually needed (rather than just being there, sometimes defined as an "optimization" - how often do people do self-assignments...?), the code is almost certainly wrong, most likely not maintaining the basic exception guarantee. As a result I recommend using the copy&swap approach unless there is a very good reason not to although I'm aware that it uses more memory (although the problem is rarely that there isn't enough memory, at least not on the systems I'm working on, but rather that use of more memory may result in slower execution).
In the forthcoming C++0x standard, what happens when an exception is thrown within/during the move constructor?
Will the original object remain? or are both the original and move-to object in an undefined state? what are the guarantees afforded by the language?
I believe that the standards committee originally attempted to make it so move constructors would not be allowed to throw exceptions, but (at least as of today) found that trying to enforce that had too many pitfalls.
Proposal N3050, "Allowing Move Constructors to Throw (Rev 1)", has been incorporated into the draft standard. Essentially the proposal adds the capability for move constructors to throw, but to disallow 'throwing' moves to be used for certain operations where strong exception safety guarantees were needed (the library will fall back to copying the object if a non-throwing move isn't available).
If you mark a move constructor as non-throwing (noexcept) and an exception is thrown, std::terminate() will be called.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html
It might also be worth reading a blog article by David Abrahams that discusses the issues that N3050 was intended to address:
http://cpp-next.com/archive/2009/10/exceptionally-moving/
Depends on the type being moved from. It's possible to explicitly throw an exception, of course, from a move ctor, but also to implicitly call a copy ctor for a subobject from a move ctor. That copy ctor might do something that may throw, such as allocate memory. So, for the source object, the minimum guarantee is the original value may or may not remain, but it should still be in a destructable state.
For the object being moved to, it's the same as throwing from a ctor in current C++: destroy any constructed bases and members, execute the ctor's function try handler, if any, then propagate the exception. Details are in N3225 §15.2p2.
In particular, note that containers require their allocator types not have throwing move ctors:
Such move construction of the allocator shall not exit via an exception. [N3225 §23.2p8]
This allows the containers to move allocators around and use those allocators to clean up their items in the case of an exception when moving or copying items.
Your question then amounts to a question about Exception Guarantees. There are 3 types of Exceptions Guarantees (that apply to functions):
No exception guarantee at all (not really a type... but it may happen if no concern is given to the matter)
Basic Exception Guarantee: Technically correct, but not Functionally correct (ie no resource is leaked, the program will terminate without an abrupt halt, but it may have undesired side-effects, like the payment being cashed-in but the command not being registered)
Strong Exception Guarantee: All or Nothing (like a transaction), that is either everything is done right, or we rollback to the previous state.
No Throw Exception Guarantee: This does not throw, ever, so no worry.
When you compose your function, you usually pick up existing functions with their own guarantees. It is difficult to increase the exception guarantee, that is your are generally limited by the weakest guarantee used.
W.r.t your question, it takes at least a Strong Exception Guarantee for the original object to be left untouched if an exception is thrown.
So, what happens if an exception is thrown during move-construction ? It depends on the guarantees exhibited by the sub-objects and the way you combined the calls...
If an exception is thrown from a constructor, the object is not being built and all built subobjects are destroyed, in reverse order. This rule is also applicable to a move-constructor
Unless you "wrap" the constructor in a try catch and somehow restore the objects that have been moved, they'll have lost their resources. Note that they must still be in a destructable state anyway, so technically the program will be correct.
In terms of exceptions guarantees, it means that by default, if all of the subobjects' constructors at least meet the Basic Exception Guarantee, then your move constructor will too, without any special care.
However, even if all the subobjects' constructors meet the Strong Exception Guarantee, it's unlikely you'll succeed in having your own move constructor meet it: this is the same issue that chaining transactions does not yield a transaction.
If only one of the subobjects' constructors may throw, and it meets the Strong Exception Guarantee, then your move constructor will naturally meet it itself if you initialize the throwing object first.
Hope this helped... exceptions are a wild beast to tame :)