我引用了这个SO答案Does D have something akin to C++0x's move semantics?
接下来,您可以通过定义此(Struct that)来覆盖C ++的构造函数(构造函数&& that)。同样,您可以使用opAssign(Struct that)覆盖赋值。在这两种情况下,您都需要确保销毁它的值。
他给出了一个这样的例子:
url('foo', [333, 'bar', 444, 'show']);
// site.com/foo/333/bar/444/show
变量// Move operations
this(UniquePtr!T that) {
this.ptr = that.ptr;
that.ptr = null;
}
总是会被移动吗?或者在某些情况下可能会复制变量that
?
如果我只在临时副本上取消ptr,那将是不幸的。
答案 0 :(得分:4)
嗯,你也可以看看这个问题:
Questions about postblit and move semantics
在D中复制结构的方式是它的内存是blitted,然后如果它有一个postblit构造函数,则调用它的postblit构造函数。如果编译器确定副本实际上不是必需的,那么它将不会调用postblit构造函数,也不会调用原始对象上的析构函数。因此,它将移动对象而不是复制它。
特别是,根据TDPL(第251页),语言保证
- 移动所有匿名rvalues,而不是复制。致电
this(this
) 当源是匿名右值时(即,a。),它永远不会被插入 临时的,如上面函数hun
中所述。)- 在函数内部堆栈分配的所有命名临时对象 然后给elide打电话
this(this)
。- 无法保证可以观察到其他潜在的分歧。
因此,在其他情况下,编译器可能会或可能不会删除副本,具体取决于当前的编译器实现和优化级别(例如,如果将左值传递给按值获取的函数,并且该变量永远不会再次引用在函数调用之后)。
所以,如果你有
void foo(Bar bar)
{}
然后foo
的参数是否被移动取决于它是左值还是右值。如果它是一个右值,它将被移动,而如果它是一个左值,它可能不会(但可能取决于调用代码和编译器)。
所以,如果你有
void foo(UniquePtr!T ptr)
{}
如果ptr
传递了右值,则会移动 foo
,并且可能会或可能不会移动
UniquePtr
传递左值(尽管通常不是)。那么,UniquePtr
的内部结构会发生什么取决于你如何实现它。如果this(UniquePtr!T that)
{
this.ptr = that.ptr;
that.ptr = null;
}
禁用postblit构造函数以使其无法复制,则传递rvalue将移动参数,并传递左值将导致编译错误(因为保证rvalue被移动,而左值则不是。
现在,你拥有的是
UniquePtr
似乎与当前类型的行为具有与其参数相同的成员。所以,我假设你实际上在这里尝试做的是UniquePtr!T
的复制构造函数/移动构造函数,而不是采用this(this)
的任意类型的构造函数。如果这就是您正在做的事情,那么您需要一个postblit构造函数 - this(this)
{
// Do any deep copying you want here. e.g.
arr = arr.dup;
}
- 而不是一个与结构本身采用相同类型的构造函数(因为D没有复制构造函数)。所以,如果您想要的是复制构造函数,那么您可以执行类似
@disable this(this);
但是如果你的struct元素的按位副本适合你的类型,那么你就不需要postblit构造函数了。但是移动是内置的,所以你不需要声明移动构造函数(移动只会使结构的成员搞砸)。相反,如果您想要保证对象被移动并且从不复制,那么您要做的就是禁用struct的postblit构造函数。 e.g。
UniquePtr!T
然后,在任何地方传递opAssign
的任何时候,它都会被保证是移动或编译错误。虽然我可能认为您可能需要单独禁用opOpAssign
以禁用分配,从它的外观(基于我刚刚测试的代码),您甚至不必单独禁用分配。禁用postblit构造函数也会禁用赋值运算符。但如果情况并非如此,那么您也必须禁用{{1}}。
答案 1 :(得分:3)
JMD答案涵盖了移动语义的理论部分,我可以通过一个非常简化的示例实现扩展它:
struct UniquePtr(T)
{
private T* ptr;
@disable this(this);
UniquePtr release()
{
scope(exit) this.ptr = null;
return UniquePtr(this.ptr);
}
}
// some function that takes argument by value:
void foo ( UniquePtr!int ) { }
auto p = UniquePtr!int(new int);
// won't compile, postblit constructor is disabled
foo(p);
// ok, release() returns a new rvalue which is
// guaranteed to be moved without copying
foo(p.release());
// release also resets previous pointer:
assert(p.ptr is null);
答案 2 :(得分:1)
我想我可以自己回答。引用"编程语言":
移动所有匿名rvalues,而不是复制。永远不会插入对此(此)的调用 当来源是一个匿名的左值(即一个临时的,如 上面的函数)。
如果我理解正确,这意味着this(Struct that)
永远不会是副本,因为它首先只接受rvalues。