I have some confusions about C move constructor. If the compiler is implicitly synthesizing a move constructor, what will this move constructor do? Will it just make "this" point to the object that is used for initialization? there's an example:
struct Foo {
int i;
int *ptr;
};
Foo x;
Foo y(std::move(x));
will the implicitly synthesized move constructor just make this
in y
point to the memory that x
is in? If so, how to ensure that x
is destructible after the move (if x
is destroyed, will members in y
be valid)? if not, how does the move constructor of y
work?
CodePudding user response:
will the implicitly synthesized move constructor just make this in y point to the memory that x is in?
The synthesized move ctor will memberwise-move the data members of its arguments(x
here) to the object being created(y
here).
Also, note that for built-in types like int
, move is the same as copying.
how to ensure that x is destructible after the move
Since move is the same as copying for built in types, x
and y
are independent of each other. So when x
is destroyed y
will not be affected.
will the synthesized move constructor set the
ptr
ofx
tonullptr
?
No, the synthesize move ctor will not do that for you. It will just memberwise move the data members. For built in types this means the same as copying.
if it does not do this, then the
ptr
ofx
will still point to the memory to which theptr
ofy
points, then you cannot safely destroyx
.
In that case, you'd need to write a user-defined move ctor which explicitly sets the ptr
of x
to nullptr
so that when x
is destroyed, the y
is not affected.
CodePudding user response:
will the implicitly synthesized move constructor just make this in y point to the memory that x is in?
As Anoop noted, it will memberwise call the move constructor on every member of the source to be moved (x
) onto the members of the destination (y
or this
if you imagine yourself "inside" that synthesized move constructor).
So in your example:
- the
int
x.i
will be moved ontoy.i
(this->i
) - the
int*
x.ptr
will be moved ontoy.ptr
(this->ptr
).
Note that these particular moves will be performed by copying.
how to ensure that x is destructible after the move (if x is destroyed, will members in y be valid)?
It's always destructible. As to if it's "valid", it depends. The default move construction was actually a copy. Two objects now point at whatever x.ptr
pointed to. If that int
was a resource "owned" by x
(maybe the resource was a 0 terminated string of ints on the heap), then you've just "shared" that resource.
If you don't wish to "share" it then you could have explicitly written a move constructor for Foo
that resets the pointer of the "moved-from" object, or somehow marks it invalid.
struct Foo {
...
Foo(Foo&& other) {
this->i = other.i;
this->ptr = other.ptr;
other.ptr = nullptr;
}
}
In general, it's best not to rely on "moved from" objects at all, i.e. make sure they are destroyed as soon as possible.