move 构造函数是否会更改“this”指向的内存?

Does move constructor change the memory to which "this" points to?

提问人:kaiyu wei 提问时间:4/10/2022 更新时间:4/10/2022 访问量:182

问:

我对C++移动构造函数有一些困惑。如果编译器隐式合成移动构造函数,则此移动构造函数将执行什么操作?它只会使“this”指向用于初始化的对象吗? 下面有一个示例:

struct Foo {
    int i;
    int *ptr;
};

Foo x;
Foo y(std::move(x));

隐式合成的 move 构造函数是否只是指向内存?如果是这样,如何确保在移动后是可破坏的(如果被破坏,成员是否有效)?如果不是,移动构造函数如何工作?thisyxxxyy

C++ 复制 复制构造函数 move-constructor

评论

0赞 WhozCraig 4/10/2022
1. 不,和 2.移动 CTOR 的工作原理(与 Copy-CTOR 的工作原理)在本站点上的大量问题中进行了详细介绍。例如这个尤其是这个

答:

2赞 user12002570 4/10/2022 #1

隐式合成的 move 构造函数是否只是在 y 中将其指向 x 所在的内存?

合成的移动 ctor 将成员式地将其参数(此处)的数据成员移动到正在创建的对象(此处)。xy

另外,请注意,对于内置类型,如 ,move 与复制相同。int


如何确保 X 在移动后是可破坏的

由于 move 与内置类型的复制相同,并且彼此独立。所以当被破坏时不会受到影响。xyxy


合成的 move 构造函数会将 OF 设置为 ?ptrxnullptr

不,合成移动 ctor 不会为您做到这一点。它只会以成员方式移动数据成员。对于内置类型,这意味着与复制相同。


如果它不这样做,那么 of 仍将指向 of 指向的内存,那么你就无法安全地销毁 .ptrxptryx

在这种情况下,您需要编写一个用户定义的移动 ctor,该 ctor 显式地将 of 设置为,以便在销毁时不受影响。ptrxnullptrxy

评论

0赞 kaiyu wei 4/10/2022
Move 构造函数如何移动 int 或 string 类型成员?它只会将这些成员的值复制到初始化的类对象中吗?
0赞 kaiyu wei 4/10/2022
而且,合成的移动构造函数会将 of 设置为 ?如果它不这样做,那么 of 仍将指向 of 指向的内存,那么你就无法安全地销毁 .ptrxnullptrptrxptryx
0赞 user12002570 4/10/2022
@kaiyuwei 对于内置类型,如 ,与复制相同。更多可以在这里找到:内置类型有移动语义吗?也就是说,对于内置类型,a 是一个副本。intmovemove
0赞 user12002570 4/10/2022
@kaiyuwei 不,合成的移动 ctor 不会将 的 设置为 。它只会以成员方式将数据成员从 移动到 ,而不执行任何其他操作。另请注意,对于内置类型数据成员,如 ,move 与复制相同。所以和是相互独立的。如果 和 的指针都指向同一内存,则需要编写自己的移动构造函数,该构造函数将设置为 nullptr。合成的 ctor 不会为您做到这一点。ptrxnullptrxyintxyxyx
0赞 user12002570 4/10/2022
@kaiyuwei 您必须编写一个用户定义的移动 ctor,它明确地将 of 设置为,以便在销毁时不受影响。ptrxnullptrxy
1赞 joao 4/10/2022 #2

隐式合成的 move 构造函数是否只是在 y 中将其指向 x 所在的内存?

正如 Anoop 所指出的,它将以成员方式调用要移动的源的每个成员上的移动构造函数 () 到目标的成员上(或者如果您想象自己“在”该合成的移动构造函数中)。xythis

所以在你的例子中:

  • 将移至intx.iy.i (this->i)
  • 将移动到 ()。int*x.ptry.ptrthis->ptr

请注意,这些特定动作将通过复制来执行。

如何确保 X 在移动后是可破坏的(如果 X 被摧毁,Y 中的成员是否有效)?

它总是可破坏的。至于它是否“有效”,这取决于。默认的移动构造实际上是一个副本。现在有两个对象指向指向的任何对象。如果这是“拥有”的资源(也许该资源是堆上以 0 结尾的 ints 字符串),那么您只是“共享”了该资源。x.ptrintx

如果你不想“共享”它,那么你可以显式地编写一个移动构造函数,用于重置“moved-from”对象的指针,或者以某种方式将其标记为无效。Foo

struct Foo {
  ...
  Foo(Foo&& other) {
    this->i = other.i;
    this->ptr = other.ptr;
    other.ptr = nullptr;
  }
}

一般来说,最好不要依赖“从”对象中移动,即确保它们尽快被销毁。

评论

0赞 kaiyu wei 4/10/2022
谢谢Joao,既然 和 指向同一个对象,你怎么能说它是可破坏的?因为如果你销毁,那么点的对象也将被销毁,这使得'''y.ptr'''无效。x.ptry.ptrxxy.ptr
0赞 joao 4/10/2022
是的,但是在您第一次发布的示例中,没有成员的这种析构函数!所以指向的东西不会被摧毁。如果存在这样的析构函数,那么该析构函数可能应该检查是否是而不是销毁它。这是我建议定义移动构造函数的一个很好的理由。ptrptrptrnullptr
0赞 kaiyu wei 4/10/2022
现在对我来说已经足够清楚了。多谢!