我正在引用这个 SO 答案Does D have something like to C++0x's move semantics?
接下来,您可以通过定义 this(Struct that) 来覆盖 C++ 的构造函数(constructor &&that)。同样,您可以使用 opAssign(Struct that) 覆盖分配。在这两种情况下,您都需要确保销毁它的值。
他举了一个这样的例子:
// Move operations
this(UniquePtr!T that) {
this.ptr = that.ptr;
that.ptr = null;
}
Run Code Online (Sandbox Code Playgroud)
变量会that 一直移动吗?或者that在某些情况下变量可能会被复制?
如果我只将临时副本上的 ptr 置空,那将是不幸的。
好吧,你也可以看看这个 SO 问题:
在D中复制struct的方式是将其内存blitted,然后如果它有postblit构造函数,则调用其postblit构造函数。如果编译器确定实际上不需要副本,则它不会调用 postblit 构造函数,也不会调用原始对象的析构函数。因此,它将移动对象而不是复制它。
- 所有匿名右值都被移动,而不是复制。
this(this当源是匿名右值(即hun上面函数中的临时值)时,永远不会插入对)的调用。- 在函数内堆栈分配的所有命名临时对象,然后返回省略对
this(this).- 不能保证观察到其他潜在的省略。
因此,在其他情况下,编译器可能会或可能不会消除副本,具体取决于当前的编译器实现和优化级别(例如,如果您将左值传递给按值获取它的函数,并且该变量在该函数之后不再被引用称呼)。
所以,如果你有
void foo(Bar bar)
{}
Run Code Online (Sandbox Code Playgroud)
那么参数是否foo被移动取决于它是右值还是左值。如果它是一个右值,它将被移动,而如果它是一个左值,它可能不会被移动(但可能取决于调用代码和编译器)。
所以,如果你有
void foo(UniquePtr!T ptr)
{}
Run Code Online (Sandbox Code Playgroud)
ptr如果foo传递了一个右值,则将被移动,并且可能会或可能不会移动它传递了一个左值(尽管通常不会)。所以,内部会发生什么UniquePtr取决于你如何实现它。如果UniquePtr禁用 postblit 构造函数使其无法被复制,则传递右值将移动参数,传递左值将导致编译错误(因为保证右值被移动,而左值不会)。
现在,你所拥有的是
this(UniquePtr!T that)
{
this.ptr = that.ptr;
that.ptr = null;
}
Run Code Online (Sandbox Code Playgroud)
看起来就像当前类型具有与其参数相同的成员。因此,我假设您在这里实际尝试做的是复制构造函数/移动构造函数,UniquePtr而不是使用UniquePtr!T. 如果这就是你正在做的,那么你需要一个 postblit 构造函数——this(this)而不是一个与结构本身具有相同类型的构造函数(因为 D 没有复制构造函数)。因此,如果您想要的是复制构造函数,那么您可以执行以下操作
this(this)
{
// Do any deep copying you want here. e.g.
arr = arr.dup;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您的结构元素的按位副本适用于您的类型,那么您就不需要 postblit 构造函数。但是移动是内置的,因此无论如何您都不需要声明移动构造函数(移动只会对结构的成员进行 blit)。相反,如果您想要的是保证对象被移动并且永远不会被复制,那么您想要做的是禁用结构的 postblit 构造函数。例如
@disable this(this);
Run Code Online (Sandbox Code Playgroud)
然后,无论何时,您在UniquePtr!T任何地方传递 a都可以保证是移动或编译错误。虽然我认为您可能必须opAssign单独禁用才能禁用分配,但从它的外观(基于我刚刚测试的代码)来看,您甚至不必单独禁用分配。禁用 postblit 构造函数也会禁用赋值运算符。但如果情况并非如此,那么您也只需要禁用即可opOpAssign。