1

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?

kaiyu wei
  • 431
  • 2
  • 5
  • 14
  • 1. No, and 2. how move ctors work (vs how copy-ctors work) is covered at length in a multitude of questions on this site. [this one for example](https://stackoverflow.com/questions/64378721/what-is-the-difference-between-the-copy-constructor-and-move-constructor-in-c). And [especially this one](https://stackoverflow.com/questions/3106110/what-is-move-semantics). – WhozCraig Apr 10 '22 at 08:28

2 Answers2

2

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 of x to nullptr?

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 of x will still point to the memory to which the ptr of y points, then you cannot safely destroy x.

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.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • how the move constructor moves the int or string type members? Will it just copy the values of these members to the initialized class object? – kaiyu wei Apr 10 '22 at 08:39
  • And, will the synthesized move constructor set the ```ptr``` of ```x``` to ```nullptr```? if it does not do this, then the ```ptr```of ```x``` will still point to the memory to which the ```ptr``` of ```y``` points, then you cannot safely destroy ```x```. – kaiyu wei Apr 10 '22 at 08:47
  • @kaiyuwei For built-in types like `int`, `move` is the same as copying. More can be found [here:Do built-in types have move semantics?](https://stackoverflow.com/questions/14679605/do-built-in-types-have-move-semantics). That is, for built in types a `move` is a copy. – Jason Apr 10 '22 at 08:57
  • @kaiyuwei No, the synthesized move ctor will not set the `ptr` of `x` to `nullptr`. It will just memberwise move the data members from `x` to `y` without doing anything else. Also note that for built in type data members like `int`, move is the same as copying. So `x` and `y` are independent of each other. If both the pointers of `x` and `y` point to the same memory, the you'll need to write your own move constructor that will set `x` to nullptr. The synthesized ctor will not do that for you. – Jason Apr 10 '22 at 09:08
  • @kaiyuwei You'd have 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. – Jason Apr 10 '22 at 09:15
1

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 onto y.i (this->i)
  • the int* x.ptr will be moved onto y.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.

joao
  • 3,517
  • 1
  • 31
  • 43
  • Thanks Joao, since the ```x.ptr``` and ```y.ptr``` are pointing to the same object, how can you say that ```x``` is destructible? since if you destroy ```x``` then the object to which ```y.ptr``` points will also be destroyed, which makes ```y.ptr''' invalid. – kaiyu wei Apr 10 '22 at 09:12
  • Right, but in the example you first posted, there was no such destructor of the `ptr` member! So the thing that `ptr` points to would *not* be destroyed. If there _were_ such a destructor, then that destructor should probably check if `ptr` is `nullptr` and not destroy it. And that is a good reason to define the move constructor as I suggested. – joao Apr 10 '22 at 09:28
  • Clear enough to me now. Thanks a lot! – kaiyu wei Apr 10 '22 at 09:43