I read in another question that when implementing a move constructor it is good practice to std::move each member in the initializer list because if the member happens to be another object then that objects move constructor will be called. Like so...
//Move constructor
Car::Car(Car && obj)
:
prBufferLength(std::move(obj.prBufferLength)),
prBuffer(std::move(obj.prBuffer))
{
obj.prBuffer = nullptr;
obj.prBufferLength = 0;
}
However in all the sample move assignment operators I've seen, there has been no mention of using std::move for the same reasons. If the member is an object then should std::move be used? Like so...
//Move assignment
Car Car::operator=(Car && obj)
{
delete[] prBuffer;
prBufferLength = std::move(obj.prBufferLength);
prBuffer = std::move(obj.prBuffer);
obj.prBuffer = nullptr;
obj.prBufferLength = 0;
return *this;
}
UPDATE:
I appreciate there is no need to use std::move in the example I have chosen (poorly) however I'm interested in if the members were objects.
After reading the linked question, I can see the advice in the second most-upvoted answer is to use std::move in the initializer list for the move constructor because no matter if it is a primitive type or not, it will do the right thing. I somewhat disagree with that and think you should only call std::move where appropriate, but this is were personal preferences come in.
Also, for your move assignment operator, the way you have it is fine although I think the unnecessary call to std::move should be removed personally. Another option is to use std::swap which will do the right thing for you.
Car Car::operator=(Car && obj)
{
std::swap(this->prBufferLength, obj.prBufferLength);
std::swap(this->prBuffer, obj.prBuffer);
return *this;
}
The difference between the above move assignment operator and your move assignment operator is that the deallocation of memory is delayed while your version deallocates the memory right away, this might be important in some situations.
It looks like prBuffer is a pointer and prBufferLength is some kind of integral type, so move isn't going to make any difference in this particular case as they are both fundamental types.
If prBuffer was a std::string for example, then you should use move to force the use of a move constructor or move assignment operator.
If your member objects would benefit from moving, you should certainly move them. Another strategy, which was demonstrated in the answer you linked to, is swapping. Swapping is like moving, but it's moving in both directions. If your class manages a resource, this has the effect of the object that was passed in (the rvalue) recieving the no longer wanted data. That data is then destroyed by that object's destructor. For example, your move assignment operator could be written like this:
Car Car::operator=(Car && obj)
{
// don't need this, it will be handled by obj's destructor
// delete[] prBuffer;
using std::swap;
swap(prBuffer, obj.prBuffer);
swap(prBufferLength, obj.prBufferLength);
return *this;
}
Also take a look at the Copy-and-Swap idiom. Which allows you to use the same assignment operator for both move and copy, but has the slight drawback that self-assignment results in an unnecessary copy.
Like a lot of things in C++ and life there isn't a definitive yes or no answer to the question.
That said, as a general rule if incoming member will be cleared / reset / emptied and assigning the incoming member to the destination member will result in an assignment operator being called, then you will want to use std::move so that the move assignment operator will be called instead of the copy assignment operator.
If an assignment operator will not be called (i.e. just a shallow copy will be done) then using std::move is not necessary.
I believe a (the?) better way to implement move assignment is to use the move constructor to create a new temporary object, and then swap it with the current object, just as with copy assignment.
It not only avoids code duplication but also prevents you from making mistakes accidentally by e.g. forgetting to move a member.
Related
I've run into a problem with std::swap. I have to swap an object. That object releases memory in its destructor. I've written a move constructor and a move assignment operator that copies the pointer to that memory. The default constructor sets that pointer to NULL.
Of course, I have a regular copy constructor and assignment operator, but they allocate and copy the memory, which is obviously not what I want for my swap operation.
When I call std::swap, it creates a temporary object from _Left using my move constructor. Then, it uses my move assignment operator to move _Right to _Left, and finally, it moves the temp object to _Right.
This all looks good when you get to the bottom of std::swap. However, when you step out of the bottom of it, the destructor for the temp object runs, freeing the memory that the _Right object is expecting to have.
What's the normal accepted way to do this? I was hoping to avoid having to write swap functions since that's the point of move constructors/move assignment operators. Do I have to use my own swap() to avoid this?
The move operation should leave the object being moved from in a destructible state, which may be a different state than how it came into the move.
If I am understanding the problem right it sounds like your object's move-ctor needs to set the pointer(s) in the object being moved from to something other than the values they came in with. A subsequent dtor on those now-moved objects should leave the memory they once referred to alone.
Okay, after a lot more study, I understand my fundamental problem and the solution.
Short Version:
In your move constructor, copy values from the source object, then set them to the value they would be if your default constructor had run.
Long Version:
When you create a move constructor or move assignment operator, you must leave the object being assigned from in a default state that can be destructed. Swapping does not accomplish this. Instead, you need to first steal the resources from the source object, then set the members of the source object to the state they would be in if a constructor had run.
One example where swapping lands you in hot water is where you're dealing with a pointer, like I was. You can't copy or swap it. If you copy the pointer, then the pointer value will still be in the source object when it gets destructed. If you swap the pointer, then it will be an uninitialized value, which will probably crash your destructor. Instead, you should copy the pointer value, then set the pointer in the source object to NULL. Of course, you must check for NULL in destructors when releasing memory.
If one of the members you're stealing is a class instance you control, then you should use std::move to copy it, since that will invoke its move assignment operator, also leaving it destructable.
Bonus:
Don't reinvent the wheel. Just invoke your move assignment operator from your move constructor.
void CObject::CObject(CObject&& other)
{
*this = std::move(other);
}
CObject& CObject::operator = (CObject&& other)
{
// m_pResource is a pointer.
// Copy the value.
m_pResource = other.m_pResource;
// Set other to default state so the destructor doesn't free it.
other.m_pResource = NULL;
// m_iCount is an int who's value does not matter in the destructor.
m_iCount = other.m_iCount;
// m_Obj is a class instance.
// Invoking move semantics will use its move assignment operator if it has one.
m_Obj = std::move(other.m_Obj);
return *this;
}
In here: http://en.m.wikipedia.org/wiki/Rule_of_three_(C++_programming)
/** Copy Assignment Operator */
Foo& operator= (const Foo& other) {
Foo temporary (other);
std::swap (data, temporary.data);
return *this;
}
In the example, it uses std::swap to swap the data with a temporary. Why would we create a temporary and swap? Isn't it faster to just copy? I saw this in other places too and got confused.
The swap trick is a fairly easy way to ensure exception safety.
If you do a field-by-field copy, and get exception in the middle, your object could end up in an inconsistent state (unless you take steps to address this, which could complicate things considerably).
With the swap-based implementation, if the Foo temporary (other) throws, your object remains unaltered from its original state.
In addition, to enable copy elision and (c++11) move semantics:
Foo& operator= (Foo other) {
std::swap(data, other.data);
return *this;
}
This is to avoid the inconsistent state or in more better word we would say to make exception safety.
You may also check this related Thread:- What is the copy-and-swap idiom?
As mentioned by GManNickG in the above thread:-
It works by using the copy-constructor's functionality to create a
local copy of the data, then takes the copied data with a swap
function, swapping the old data with the new data. The temporary copy
then destructs, taking the old data with it. We are left with a copy
of the new data.
In order to use the copy-and-swap idiom, we need three things: a
working copy-constructor, a working destructor (both are the basis of
any wrapper, so should be complete anyway), and a swap function.
A swap function is a non-throwing function that swaps two objects of a
class, member for member. We might be tempted to use std::swap instead
of providing our own, but this would be impossible; std::swap uses the
copy-constructor and copy-assignment operator within its
implementation, and we'd ultimately be trying to define the assignment
operator in terms of itself!
Also check Why do some people use swap for move assignments?
Background:
I have a complicated class with many variables. I have a sound and tested copy constructor:
Applepie::Applepie( const Applepie ©) :
m_crust(copy.m_crust),
m_filling(copy.m_filling)
{
}
Some of the member variable copy constructors called in the intializer list perform allocation.
Question:
I need to create operator=. Rather than duplicating the existing constuctor with assignment instead of initialization list, and freeing memory that's being replaced, and etc etc etc, can I simply do the following:
Applepie& Applepie::operator=( const Applepie ©)
{
if( this != ©)
{
this->~Applepie(); // release own object
new(this) Applepie(copy); // placement new copy constructor
}
return *this;
}
In other words, is destroy self followed by a placement new copy constructor semantically identical to operator= ?
This seems to have the potential to dramatically reduce repeat code and confirming that each variable is initialized properly, at the cost of potential slight loss of efficiency during assignment. Am I missing something more obscure?
Rationale:
My actual class has about 30 varaibles. I am concerned about the fact that both my copy constructor and my assignment operator have to copy all thirty, and that the code might diverge, causing the two operations to do things differently.
As Herb Sutter in "Exceptional C++" states, it is not exception safe. That means, if anything is going wrong during new or construction of the new object, the left hand operand of the assignment is in bad (undefined) state, calling for more trouble. I would strongly recommend using the copy & swap idiom.
Applepie& Applepie::operator=(Applepie copy)
{
swap(m_crust, copy.m_crust);
swap(m_filling, copy.m_filling);
return *this;
}
When your object uses the Pimpl idiom (pointer to implementation) also, the swap is done by changing only two pointers.
In addition to Rene's answer, there is also the problem of what would happen if ApplePie was a base class of the actual object: ApplePie would be replacing the object with an object of the wrong type!
If the operator= is properly defined, is it OK to use the following as copy constructor?
MyClass::MyClass(MyClass const &_copy)
{
*this = _copy;
}
If all members of MyClass have a default constructor, yes.
Note that usually it is the other way around:
class MyClass
{
public:
MyClass(MyClass const&); // Implemented
void swap(MyClass&) throw(); // Implemented
MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
};
We pass by value in operator= so that the copy constructor gets called. Note that everything is exception safe, since swap is guaranteed not to throw (you have to ensure this in your implementation).
EDIT, as requested, about the call-by-value stuff: The operator= could be written as
MyClass& MyClass::operator=(MyClass const& rhs)
{
MyClass tmp(rhs);
tmp.swap(*this);
return *this;
}
C++ students are usually told to pass class instances by reference because the copy constructor gets called if they are passed by value. In our case, we have to copy rhs anyway, so passing by value is fine.
Thus, the operator= (first version, call by value) reads:
Make a copy of rhs (via the copy constructor, automatically called)
Swap its contents with *this
Return *this and let rhs (which contains the old value) be destroyed at method exit.
Now, we have an extra bonus with this call-by-value. If the object being passed to operator= (or any function which gets its arguments by value) is a temporary object, the compiler can (and usually does) make no copy at all. This is called copy elision.
Therefore, if rhs is temporary, no copy is made. We are left with:
Swap this and rhs contents
Destroy rhs
So passing by value is in this case more efficient than passing by reference.
It is more advisable to implement operator= in terms of an exception safe copy constructor. See Example 4. in this from Herb Sutter for an explanation of the technique and why it's a good idea.
http://www.gotw.ca/gotw/059.htm
This implementation implies that the default constructors for all the data members (and base classes) are available and accessible from MyClass, because they will be called first, before making the assignment. Even in this case, having this extra call for the constructors might be expensive (depending on the content of the class).
I would still stick to separate implementation of the copy constructor through initialization list, even if it means writing more code.
Another thing: This implementation might have side effects (e.g. if you have dynamically allocated members).
While the end result is the same, the members are first default initialized, only copied after that.
With 'expensive' members, you better copy-construct with an initializer list.
struct C {
ExpensiveType member;
C( const C& other ): member(other.member) {}
};
};
I would say this is not okay if MyClass allocates memory or is mutable.
yes.
personally, if your class doesn't have pointers though I'd not overload the equal operator or write the copy constructor and let the compiler do it for you; it will implement a shallow copy and you'll know for sure that all member data is copied, whereas if you overload the = op; and then add a data member and then forget to update the overload you'll have a problem.
#Alexandre - I am not sure about passing by value in assignment operator. What is the advantage you will get by calling copy constructor there? Is this going to fasten the assignment operator?
P.S. I don't know how to write comments. Or may be I am not allowed to write comments.
It is technically OK, if you have a working assignment operator (copy operator).
However, you should prefer copy-and-swap because:
Exception safety is easier with copy-swap
Most logical separation of concerns:
The copy-ctor is about allocating the resources it needs (to copy the other stuff).
The swap function is (mostly) only about exchanging internal "handles" and doesn't need to do resource (de)allocation
The destructor is about resource deallocation
Copy-and-swap naturally combines these three function in the assignment/copy operator
I searched how to implement + operator properly all over the internet and all the results i found do the following steps :
const MyClass MyClass::operator+(const MyClass &other) const
{
MyClass result = *this; // Make a copy of myself. Same as MyClass result(*this);
result += other; // Use += to add other to the copy.
return result; // All done!
}
I have few questions about this "process" :
Isn't that stupid to implement + operator this way, it calls the assignment operator(which copies the class) in the first line and then the copy constructor in the return (which also copies the class , due to the fact that the return is by value, so it destroys the first copy and creates a new one.. which is frankly not really smart ... )
When i write a=b+c, the b+c part creates a new copy of the class, then the 'a=' part copies the copy to himself.
who deletes the copy that b+c created ?
Is there a better way to implement + operator without coping the class twice, and also without any memory issues ?
thanks in advance
That's effectively not an assignment operator, but a copy constructor. An operation like addition creates a new value, after all, so it has to be created somewhere. This is more efficient than it seems, since the compiler is free to do Return Value Optimization, which means it can construct the value directly where it will next be used.
The result is declared as a local variable, and hence goes away with the function call - except if RVO (see above) is used, in which case it was never actually created in the function, but in the caller.
Not really; this method is much more efficient than it looks at first.
Under the circumstances, I'd probably consider something like:
MyClass MyClass::operator+(MyClass other) {
other += *this;
return other;
}
Dave Abrahams wrote an article a while back explaining how this works and why this kind of code is usually quite efficient even though it initially seems like it shouldn't be.
Edit (thank you MSalters): Yes, this does assume/depend upon the commutative property holding for MyClass. If a+b != b+a, then the original code is what you want (most of the same reasoning applies).
it calls the assignment operator(which copies the class) in the first line
No, this is copy-initialization (through constructor).
then the copy constructor in the return (which also copies the class
Compilers can (and typically do) elide this copy using NRVO.
When i write a=b+c, the b+c part creates a new copy of the class, then the 'a=' part copies the copy to himself. who deletes the copy that b+c created
The compiler, as any other temporary value. They are deleted at the end of full-expression (in this case, it means at or after ; at the end of line.
Is there a better way to implement + operator without coping the class twice, and also without any memory issues ?
Not really. It's not that inefficient.
This appears to be the correct way to implement operator+. A few points:
MyClass result = *this does not use the assignment operator, it should be calling the copy constructor, as if it were written MyClass result(*this).
The returned value when used in a = b + c is called a temporary, and the compiler is responsible for deleting it (which will probably happen at the end of the statement ie. the semicolon, after everything else has been done). You don't have to worry about that, the compiler will always clean up temporaries.
There's no better way, you need the copy. The compiler, however, is allowed to optimise away the temporary copies, so not as many as you think may be made. In C++0x though, you can use move constructors to improve performance by transfering ownership of the content of a temporary rather than copying it in its entirity.
I'll try my best to answer:
Point (1): No, it does not call the assignment operator. Instead it calls a constructor. Since you need to construct the object anyway (since operator+ returns a copy), this does not introduce extra operations.
Point (2): The temporary result is created in stack and hence does not introduce memory problem (it is destroyed when function exits). On return, a temporary is created so that an assignment (or copy constructor) can be used to assign the results to a (in a=b+c;) even after result is destroyed. This temporary is destroyed automatically by the compiler.
Point (3): The above is what the standard prescribes. Remember that compiler implementors are allowed to optimize the implementation as long as the effect is the same as what the standard prescribed. I believe, compilers in reality optimize away many of the copying that occurs here. Using the idiom above is readable and is not actually inefficient.
P.S. I sometime prefer to implement operator+ as a non-member to leverage implicit conversion for both sides of the operators (only if it makes sense).
There are no memory issues (provided that the assignment operator, and copy constructor are well written). Simply because all the memory for these objects is taken on the stack and managed by the compiler. Furthermore, compilers do optimize this and perform all the operations directly on the final a instead of copying twice.
This is the proper way of implementing the operator+ in C++. Most of the copies you are so afraid of will get elided by the compiler and will be subject to move semantics in C++0x.
The class is a temporary and will be deleted. If you bind the temporary to a const& the life time of the temporary will be extended to the life time of the const reference.
May implementing it as a freefunction is a little more obvious. The first parameter in MyClass::operator+ is an implicit this and the compiler will rewrite the function to operator+(const MyClass&, const MyClass&) anyway.
As far as I remember, Stroustrup's 'The C++ Programming Language' recommends to implement operators as member functions only when internal representation is affected by operation and as external functions when not. operator+ does not need to access internal representation if implemented based on operator+=, which does.
So you would have:
class MyClass
{
public:
MyClass& operator+=(const MyClass &other)
{
// Implementation
return *this;
}
};
MyClass operator+(const MyClass &op1, const MyClass &op2)
{
MyClass r = op1;
return r += op2;
}