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;
}
Related
I've been trying to fully understand move semantics, but I have one question, as different examples show different things. Say we have a class Foo that has a string member str_. To define the move constructor, should I define it like this:
Foo(Foo&& foo) : str_(foo.str_) { }
or this:
Foo(Foo&& foo) : str_(std::move(foo.str_)) { }
Also, would I need to set the members of the object i am moving from to a blank value? How would I do so without constructing another string, essentially nullifying the expense saved by using a move constructor in the first place?
You should use the second approach.
You do not have to do anything to the string you move from, because this is handled by string's move constructor. The latter is invoked by the move() call.
The same goes for your own classes, anything you want to move() should have a move constructor. For instance, if your class has a pointer member, your move constructor could/should assign nullptr to that member in the object you move() from.
In a move constructor (or move assignment operator), you need to use std::move() when moving individual members (or at least, on non-POD members, since "moving" a POD type is the same as copying it).
In Foo&& foo, foo is an rvalue reference, but foo.str_ is not. If you call str_(foo.str_) in your move constructor (or str_ = foo.str_ in your move assignment operator), it will call the string's copy constructor (or copy assignment operator). So you need to cast foo.str_ to an rvalue reference via std::move() in order to invoke the string's move constructor (or move assignment operator).
A move constructor (and move assignment operator) is responsible for leaving the moved-from object in an unspecified but valid state, so its destructor will not fail. In the case of moving the foo.str_ member, the string's move constructor (or move assignment operator) will reset foo.str_ to an empty string for you, you do not need to reset it manually.
I am looking at some code that I have inherited and it has a matrix class which implements 2D matrices in C++ and has move constructors and assignment operator.
The way it is implemented is as follows:
template<typename T, int rows, int cols>
class matrix_data {
...
std::unique_ptr<T[]> data_;
// Some definitions
typedef matrix_data<T, rows, cols> this_type
matrix_data(this_type && other)
{
std::swap(data_, other.data_);
}
};
Now, I am not sure why the data pointers are being swapped here. I thought it should be something like
data_ = std::move(other.data_);
I am guessing with the swap it is still ok because the other instance should be in an invalid state anyway after the move.
My question is whether I can replace the statement with data_ = std::move(other.data_); Is there some unique_ptr deletion stuff that is the reason for doing the swap instead of the move i.e. if I do the move would the original data be deleted correctly?
To answer your question:
Yes, you could replace the swapping with
data_ = std::move(other.data_);
but as the comments suggest, that's happening anyway when you do not implement the move constructor, as long as you do not implement neither a copy constructor, copy assignment operator, move assignment operator or destructor. If you have implemented one of the above, marking the move constructor as =default will also do the job.
Swapping the objects' contents is indeed not necessary in this case as there is actually nothing to swap, because this being a (move) constructor, this->data_ does not point to any previously allocated memory location that should be freed after the pointer to it has been overwritten.
Therefore swapping is usually done when implementing the move assignment operator, because in this case this->data_ usually holds a pointer to a memory location that needs to be freed sometime. By putting this pointer into the moved-from object, the memory it is pointing to will be freed when the destructor for the moved-from object is called.
The title pretty much sums up my question. In more detail: I know that when I declare a move constructor and a move assignment operator in C++11 I have to "make the other objects variables zero". But how does that work, when my variable is not an array or a simple int or double value, but its a more "complex" type?
In this example I have a Shoplist class with a vector member variable. Do I have to invoke the destructor of the vector class in the move assignment operator and constructor? Or what?
class Shoplist {
public:
Shoplist() :slist(0) {};
Shoplist(const Shoplist& other) :slist(other.slist) {};
Shoplist(Shoplist&& other) :slist(0) {
slist = other.slist;
other.slist.~vector();
}
Shoplist& operator=(const Shoplist& other);
Shoplist& operator=(Shoplist&& other);
~Shoplist() {};
private:
vector<Item> slist;
};
Shoplist& Shoplist::operator=(const Shoplist& other)
{
slist = other.slist;
return *this;
}
Shoplist& Shoplist::operator=(Shoplist&& other)
{
slist = other.slist;
other.slist.~vector();
return *this;
}
Whatever a std::vector needs to do in order to move correctly, will be handled by its own move constructor.
So, assuming you want to move the member, just use that directly:
Shoplist(Shoplist&& other)
: slist(std::move(other.slist))
{}
and
Shoplist& Shoplist::operator=(Shoplist&& other)
{
slist = std::move(other.slist);
return *this;
}
In this case, you could as AndyG points out, just use = default to have the compiler generate exactly the same move ctor and move assignment operator for you.
Note that explicitly destroying the original as you did is definitely absolutely wrong. The other member will be destroyed again when other goes out of scope.
Edit: I did say assuming you want to move the member, because in some cases you might not.
Generally you want to move data members like this if they're logically part of the class, and much cheaper to move than copy. While std::vector is definitely cheaper to move than to copy, if it holds some transient cache or temporary value that isn't logically part of the object's identity or value, you might reasonably choose to discard it.
Implementing copy/move/destructor operations doesn't make sense unless your class is managing a resource. By managing a resource I mean be directly responsible for it's lifetime: explicit creation and destruction. The rule of 0 and The rule of 3/5 stem from this simple ideea.
You might say that your class is managing the slist, but that would be wrong in this context: the std::vector class is directly (and correctly) managing the resources associated with it. If you let our class have implicit cpy/mv ctos/assignment and dtors, they will correctly invoke the corresponding std::vector operations. So you absolutely don't need to explicitly define them. In your case the rule of 0 applies.
I know that when I declare a move constructor and a move assignment
operator in C++11 I have to "make the other objects variables zero"
Well no, not really. The ideea is that when you move from an object (read: move it's resource from an object) then you have to make sure that your object it's left aware that the resource it had is no more under it's ownership (so that, for instance, it doesn't try to release it in it's destructor). In the case of std::vector, it's move ctor would set the pointer it has to the internal buffer to nullptr.
I know that when I declare a move constructor and a move assignment operator in C++11 I have to "make the other objects variables zero"
This is not quite correct. What you must do, is maintain validity of the moved from object. This means that you must satisfy the class invariant.
If you have specified a special invariant for a particular class, that requires you to set member variables to zero, then perhaps such class might have to do so. But this is not a requirement for move in general.
Do I have to invoke the destructor of the vector class in the move assignment operator and constructor?
Definitely not. The destructors of the members will be called when the moved from object is destroyed.
What you would typically do, is move construct/assign each member in the move constructor/assignment operator of the containing object. This is what the implicitly generated special member functions do. Of course, this might not satisfy the class invariant for all classes, and if it doesn't, then you may need to write your own versions of them.
The compiler will implicitly generate the special member functions for you, if you don't try to declare them yourself. Here is a minimal, but correct version of your class:
class Shoplist {
vector<Item> slist;
};
This class is default constructible, movable and copyable.
The move constructor should move member-wise:
Shoplist(Shoplist&& other)
: slist(std::move(other.slist))
{}
Note, that the compiler generates move constructors for you (when possible) by member-wise move, as you would do by hand above.
Move constructors are allowed (but not required) "steal" the contents of the moved-from object. This does not mean that they must "make the other objects variables zero". Moving a primitive type, for instance, is equivalent to copying it. What it does mean is that a move constructor can transfer ownership of data in the heap or free store. In this case, the moved-from object must be modified so that when it is destroyed (which should not happen in the move-constructor), the data it previously owned (before it was transferred) will not be freed.
Vector provides its own move constructor. So all you need to do in order to write a correct move constructor for an object containing a vector is to ensure the correct vector constructor is invoked. This is done by explicitly passing an r-value reference to the sub-object constructor, using std::move:
Shoplist(Shoplist&& other) :slist(std::move(other.slist)) {
//... Constructor body
... But in fact you probably don't need to do this in general. Your copy and move constructors will be correctly auto-generated if you don't declare them and don't declare a destructor. (Following this practice is called the "rule of 0".)
Alternatively, you can force the compiler to auto-generate the move constructor:
Shoplist(Shoplist&& other) = default;
C++11 introduced a new concept of rvalue reference. I was reading it somewhere and found following:
class Base
{
public:
Base() //Default Ctor
Base(int t) //Parameterized Ctor
Base(const Base& b) //Copy Ctor
Base(Base&& b) //Move Ctor
};
void foo(Base b) //Function 1
{}
void foo(Base& b) //Function 2
{}
int main()
{
Base b(10);
foo(b); -- Line 1 (i know of ambiquity but lets ignore for understanding purpose)
foo(Base()); -- Line 2
foo(2) ; -- Line 3
}
Now with my limited understanding, my observations are as follows :
Line 1 will simply call the copy constructor as argument is an lvalue.
Line 2 before C++11 would have called copy constructor and all those temporary copy stuff, but with move constructor defined, that would be called here.
Line 3 will again call move constructor as 2 will be implicitly converted to Base type (rvalue).
Please correct and explain if any of above observation is wrong.
Now, here'r my questions :
I know once we move an object it's data will be lost at calling location. So, i above example how can i change Line 2 to move object "b" in foo (is it using std::move(b) ?).
I have read move constructor is more efficient than copy constructor. How? I can think of only situation where we have memory on heap need not to be allocated again in case of move constructor. Does this statement hold true when we don't have any memory on heap?
Is it even more efficient than passing by reference (no, right?)?
First on your "understandings":
As I can see it, they are in principle right but you should be aware of Copy elision which could prevent the program from calling any copy/move Constructor. Depends on your compiler (-settings).
On your Questions:
Yes you have to call foo(std::move(b)) to call an Function which takes an rvalue with an lvalue. std::move will do the cast. Note: std::move itself does not move anything.
Using the move-constructor "might" be more efficient. In truth it only enables programmers to implement some more efficient Constructors. Example consider a vector which is a Class around a pointer to an array which holds the data (similar to std::vector), if you copy it you have to copy the data, if you move it you can just pass the pointer and set the old one to nullptr.
But as I read in Effective Modern C++ by Scott Meyers: Do not think your program will be faster only because you use std::move everywere.
That depends on the usage of the input. If you do not need a copy in the function it will in the most cases be more efficient to just pass the object by (const) reference. If you need a copy there are several ways of doing it for example the copy and swap idiom. But as a
Line 2 before C++11 would have called copy constructor and all those temporary copy stuff, but with move constructor defined, that would be called here.
Correct, except any decent optimizer would "elide" the copy, so that before C++11 the copy would have been avoided, and post C++11 the move would have been avoided. Same for line 3.
I know once we move an object it's data will be lost at calling location.
Depends on how the move constructor/assignment is implemented. If you don't know, this is what you must assume.
So, i above example how can i change Line 2 to move object "b" in foo (is it using std::move(b) ?).
Exactly. std::move changes the type of the expression into r-value and therefore the move constructor is invoked.
I have read move constructor is more efficient than copy constructor.
It can be, in some cases. For example the move constructor of std::vector is much faster than copy.
I can think of only situation where we have memory on heap need not to be allocated again in case of move constructor. Does this statement hold true when we don't have any memory on heap?
The statement isn't universally true, since for objects with trivial copy constructor, the move constructor isn't any more efficient. But owning dynamic memory isn't strictly a requirement for a more efficient move. More generally, move may can be efficient if the object owns any external resource, which could be dynamic memory, or it could be for example a reference counter or a file descriptor that must be released in the destructor and therefore re-aquired or re-calculated on copy - which can be avoided on move.
Is it even more efficient than passing by reference (no, right?)?
Indeed not. However, if you intend to move the object within the function where you pass it by reference, then you would have to pass a non-const reference and therefore not be able to pass temporaries.
In short: Reference is great for giving temporary access to an object that you keep, move is great for giving the ownership away.
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.