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
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?
Say I have a class which manages memory and thus needs user-defined special member functions (imagine vector or similar).
Consider the following implementation of the move-assignment operator:
Class& operator=(Class&& rhs)
{
this->~Class(); // call destructor
new (this) Class(std::move(rhs)); // call move constructor in-place
}
Is it valid to implement a move-assignment operator this way? That is, does calling a destructor and constructor in this way not run afoul of any object lifetime rules in the language?
Is it a good idea to implement a move-assignment operator this way? If not, why not, and is there a better canonical way?
It's not valid: What if this move assignment is called as part of moving a child object? Then you destroy the child (assuming it has a virtual destructor) and recreate in its place a parent object.
I would say that even in a non-virtual context it's still a bad idea because you don't see the syntax very often and it may make the code harder to grok for future maintainers.
The best approach is to avoid having to write your own move constructor entirely (and using the default) by having all your class members take care of moving themselves. For example rely on unique_ptr, etc. Failing that it seems that implementing it in terms of swap (as the copy-and-swap for copy assignment) would be an easily understandable mechanism.
It may be valid(1). To address your specific issue about dtor/ctor lifetimes, yes that is valid(2). That is how the original implementation for vector worked.
It may be a good idea (it probably isn't), but you may not want a canonical way.(3)
(1) There is controversy about whether or moves need to be valid in the self-move case.
Arguing for self-move safety is the position that code should be safe (duh), we certainly expect self assignment to be safe. Also some user experience reports that for many algorithms which use move, self-move is possible and tedious to check for.
Arguing against self-move safety is the position that the whole point of move semantics is time savings and for that reason moves should be as fast as possible. A self-move check can be expensive relative to the cost of a move. Note that the compiler will never generate self-move code, because natural (not casted) rvalues can't be self-moved. The only way to have a self-move is if a "std::move()" cast is explicitly invoked. This puts the burden on the caller of std::move() to either verify that self-move isn't involved or convince themselves that it isn't. Note also that it would be trivial to create a user defined equivalent of "std::move" that checked for self-move and then did nothing. If you don't support self-move, you might want to document that.
(2) This is not a template so you can know if the expression "new (this) Class(std::move(rhs));" can throw. If it can, then no, this isn't valid.
(3) This code may be a puzzle to maintainers, who might expect a more traditional swap approach, but there is a potential drawbacks to the swap approach. If the resources being released by the target need to be released as soon as possible (such as a mutex), then swap has the drawback that the resources are swapped into the move source object. If the move is the result of a call to "std::move()" the move source object may not be immediately disposed of. (Since this isn't a template you can know what resources are being freed. If memory is the only resource being freed, then this isn't an issue.)
A better approach might be to factor out the resource freeing code from the destructor and the resource moving code from the move constructor and then just call those (inlined) routines in this move assignment operator.
Copy constructors were traditionally ubiquitous in C++ programs. However, I'm doubting whether there's a good reason to that since C++11.
Even when the program logic didn't need copying objects, copy constructors (usu. default) were often included for the sole purpose of object reallocation. Without a copy constructor, you couldn't store objects in a std::vector or even return an object from a function.
However, since C++11, move constructors have been responsible for object reallocation.
Another use case for copy constructors was, simply, making clones of objects. However, I'm quite convinced that a .copy() or .clone() method is better suited for that role than a copy constructor because...
Copying objects isn't really commonplace. Certainly it's sometimes necessary for an object's interface to contain a "make a duplicate of yourself" method, but only sometimes. And when it is the case, explicit is better than implicit.
Sometimes an object could expose several different .copy()-like methods, because in different contexts the copy might need to be created differently (e.g. shallower or deeper).
In some contexts, we'd want the .copy() methods to do non-trivial things related to program logic (increment some counter, or perhaps generate a new unique name for the copy). I wouldn't accept any code that has non-obvious logic in a copy constructor.
Last but not least, a .copy() method can be virtual if needed, allowing to solve the problem of slicing.
The only cases where I'd actually want to use a copy constructor are:
RAII handles of copiable resources (quite obviously)
Structures that are intended to be used like built-in types, like math vectors or matrices -
simply because they are copied often and vec3 b = a.copy() is too verbose.
Side note: I've considered the fact that copy constructor is needed for CAS, but CAS is needed for operator=(const T&) which I consider redundant basing on the exact same reasoning;
.copy() + operator=(T&&) = default would be preferred if you really need this.)
For me, that's quite enough incentive to use T(const T&) = delete everywhere by default and provide a .copy() method when needed. (Perhaps also a private T(const T&) = default just to be able to write copy() or virtual copy() without boilerplate.)
Q: Is the above reasoning correct or am I missing any good reasons why logic objects actually need or somehow benefit from copy constructors?
Specifically, am I correct in that move constructors took over the responsibility of object reallocation in C++11 completely? I'm using "reallocation" informally for all the situations when an object needs to be moved someplace else in the memory without altering its state.
The problem is what is the word "object" referring to.
If objects are the resources that variables refers to (like in java or in C++ through pointers, using classical OOP paradigms) every "copy between variables" is a "sharing", and if single ownership is imposed, "sharing" becomes "moving".
If objects are the variables themselves, since each variables has to have its own history, you cannot "move" if you cannot / don't want to impose the destruction of a value in favor of another.
Cosider for example std::strings:
std::string a="Aa";
std::string b=a;
...
b = "Bb";
Do you expect the value of a to change, or that code to don't compile? If not, then copy is needed.
Now consider this:
std::string a="Aa";
std::string b=std::move(a);
...
b = "Bb";
Now a is left empty, since its value (better, the dynamic memory that contains it) had been "moved" to b. The value of b is then chaged, and the old "Aa" discarded.
In essence, move works only if explicitly called or if the right argument is "temporary", like in
a = b+c;
where the resource hold by the return of operator+ is clearly not needed after the assignment, hence moving it to a, rather than copy it in another a's held place and delete it is more effective.
Move and copy are two different things. Move is not "THE replacement for copy". It an more efficient way to avoid copy only in all the cases when an object is not required to generate a clone of itself.
Short anwer
Is the above reasoning correct or am I missing any good reasons why logic objects actually need or somehow benefit from copy constructors?
Automatically generated copy constructors are a great benefit in separating resource management from program logic; classes implementing logic do not need to worry about allocating, freeing or copying resources at all.
In my opinion, any replacement would need to do the same, and doing that for named functions feels a bit weird.
Long answer
When considering copy semantics, it's useful to divide types into four categories:
Primitive types, with semantics defined by the language;
Resource management (or RAII) types, with special requirements;
Aggregate types, which simply copy each member;
Polymorphic types.
Primitive types are what they are, so they are beyond the scope of the question; I'm assuming that a radical change to the language, breaking decades of legacy code, won't happen. Polymorphic types can't be copied (while maintaining the dynamic type) without user-defined virtual functions or RTTI shenanigans, so they are also beyond the scope of the question.
So the proposal is: mandate that RAII and aggregate types implement a named function, rather than a copy constructor, if they should be copied.
This makes little difference to RAII types; they just need to declare a differently-named copy function, and users just need to be slightly more verbose.
However, in the current world, aggregate types do not need to declare an explicit copy constructor at all; one will be generated automatically to copy all the members, or deleted if any are uncopyable. This ensures that, as long as all the member types are correctly copyable, so is the aggregate.
In your world, there are two possibilities:
Either the language knows about your copy-function, and can automatically generate one (perhaps only if explicitly requested, i.e. T copy() = default;, since you want explicitness). In my opinion, automatically generating named functions based on the same named function in other types feels more like magic than the current scheme of generating "language elements" (constructors and operator overloads), but perhaps that's just my prejudice speaking.
Or it's left to the user to correctly implement copying semantics for aggregates. This is error-prone (since you could add a member and forget to update the function), and breaks the current clean separation between resource management and program logic.
And to address the points you make in favour:
Copying (non-polymorphic) objects is commonplace, although as you say it's less common now that they can be moved when possible. It's just your opinion that "explicit is better" or that T a(b); is less explicit than T a(b.copy());
Agreed, if an object doesn't have clearly defined copy semantics, then it should have named functions to cover whatever options it offers. I don't see how that affects how normal objects should be copied.
I've no idea why you think that a copy constructor shouldn't be allowed to do things that a named function could, as long as they are part of the defined copy semantics. You argue that copy constructors shouldn't be used because of artificial restrictions that you place on them yourself.
Copying polymorphic objects is an entirely different kettle of fish. Forcing all types to use named functions just because polymorphic ones must won't give the consistency you seem to be arguing for, since the return types would have to be different. Polymorphic copies will need to be dynamically allocated and returned by pointer; non-polymorphic copies should be returned by value. In my opinion, there is little value in making these different operations look similar without being interchangable.
One case where copy constructors come in useful is when implementing the strong exception guarantees.
To illustrate the point, let's consider the resize function of std::vector. The function might be implemented roughly as follows:
void std::vector::resize(std::size_t n)
{
if (n > capacity())
{
T *newData = new T [n];
for (std::size_t i = 0; i < capacity(); i++)
newData[i] = std::move(m_data[i]);
delete[] m_data;
m_data = newData;
}
else
{ /* ... */ }
}
If the resize function were to have a strong exception guarantee we need to ensure that, if an exception is thrown, the state of the std::vector before the resize() call is preserved.
If T has no move constructor, then we will default to the copy constructor. In this case, if the copy constructor throws an exception, we can still provide strong exception guarantee: we simply delete the newData array and no harm to the std::vector has been done.
However, if we were using the move constructor of T and it threw an exception, then we have a bunch of Ts that were moved into the newData array. Rolling this operation back isn't straight-forward: if we try to move them back into the m_data array the move constructor of T may throw an exception again!
To resolve this issue we have the std::move_if_noexcept function. This function will use the move constructor of T if it is marked as noexcept, otherwise the copy constructor will be used. This allows us to implement std::vector::resize in such a way as to provide a strong exception guarantee.
For completeness, I should mention that C++11 std::vector::resize does not provide a strong exception guarantee in all cases. According to www.cplusplus.com we have the the follow guarantees:
If n is less than or equal to the size of the container, the function never throws exceptions (no-throw guarantee).
If n is greater and a reallocation happens, there are no changes in the container in case of exception (strong guarantee) if the type of the elements is either copyable or no-throw moveable.
Otherwise, if an exception is thrown, the container is left with a valid state (basic guarantee).
Here's the thing. Moving is the new default- the new minimum requirement. But copying is still often a useful and convenient operation.
Nobody should bend over backwards to offer a copy constructor anymore. But it is still useful for your users to have copyability if you can offer it simply.
I would not ditch copy constructors any time soon, but I admit that for my own types, I only add them when it becomes clear I need them- not immediately. So far this is very, very few types.
I've been reading some contradicting articles in regards whether move constructors/assignment is allowed to throw or not.
Therefore I'd like to ask whether move constructors/assignments are allowed to throw in the final C++11 standard?
Are move constructors in general allowed to throw? Yes. Should they? No.
In general, nothing you do within them should be anything that could throw. You shouldn't be allocating memory, calling other code, or anything like that. The only reason to write a move constructor is to abscond with someone else's memory pointers and object references. You should be copying a few basic types and nulling out the values in the other object. Those things shouldn't throw.
So while it is allowed, it's not a good idea. If you're doing it, rethink what you're doing in your move operations.
Here's to shed some further light on this.
It seems that std::vector in particular is picky about whether or not you declare your move constructors with noexcept. If you do, then std::vector will use them. If you don't then std::vector will resort to using your copy constructor instead. At least in some cases. Notably whenever it reshuffles items internally, after an internal array resize.
You can see the effects in this example, where noexcept is not declared:
http://coliru.stacked-crooked.com/a/285cd07a9a52da3b
And in this example, where it is:
http://coliru.stacked-crooked.com/a/d043774ec4c279ec
In the first example, std::vector uses the copy constructor already at the second and third insertion with push_back. In the second example, it does the same operation, but with the move constructor instead.
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
}
};