外部资源的“值类型”问题(例如 std::vector<T> 或者 std::string)是复制它们往往非常昂贵,并且副本是在各种上下文中隐式创建的,因此这往往是一个性能问题。C++0x 对这个问题的答案是 移动语义, ,其概念上基于资源窃取的思想,技术上由 右值引用.

D 有类似移动语义或右值引用的东西吗?

有帮助吗?

解决方案

我认为有在d几个地方(诸如返回结构),该d管理,使它们移动,而C ++会使他们的副本。 IIRC,编译器会做的举动,而不是在它可以确定不需要拷贝任何情况下副本,因此结构复制将在d比C ++发生较小。当然,因为类是引用,他们没有问题的。

但不管,复制结构已经工作方式不同在d比在C ++。一般情况下,代替声明拷贝构造函数,你声明postblit构造:this(this)。它this(this)前全的memcpy被调用,你只能让任何变化是必要的,以确保新的结构是从原来的独立(如做在需要成员变量的深层副本),而不是创建一个全新的构造函数必须复制的一切。所以,一般的方法是从已有的C ++有点不同。它也普遍认为在该结构不应该有昂贵postblit构造 - 复制结构应该是廉价的 - 所以这是一个问题的不到它会在C ++。这将是昂贵的复制对象通常要么是类或结构,参照或COW语义。

集装箱通常是引用类型(在火卫一,他们是结构而不是类,因为它们不需要多态性,但将它们复制并不会复制它们的内容,所以他们仍然引用类型),所以复制身边不贵像它会在C ++。

有很可能是在d情况下,它可以使用类似的举动构造函数的东西,但总的来说,d,设计了这样一种方式,以减少问题,C ++与各地复制对象,所以它的无处近,这是在C ++中的问题。

其他提示

D 具有单独的值和对象语义:

  • 如果你将你的类型声明为 struct, ,默认有值语义
  • 如果你将你的类型声明为 class, ,它将具有对象语义。

现在,假设您不自己管理内存,因为这是 D 中的默认情况 - 使用垃圾收集器 - 您必须理解声明为的类型的对象 class 自动指向真实对象的指针(或“引用”,如果您愿意),而不是真实对象本身。

因此,当在 D 中传递向量时,您传递的是引用/指针。自动地。不涉及任何副本(除了参考文献的副本)。

这就是为什么 D、C#、Java 和其他语言“不需要”移动语义(因为大多数类型是对象语义,并且通过引用而不是通过复制进行操作)。

也许他们可以实施它,我不确定。但它们真的能像 C++ 那样获得性能提升吗?从本质上来说,这似乎不太可能。

我莫名其妙地有一种感觉,其实是右值引用和“移动语义”的整个概念是一个结果,它是用C ++正常创建本地,“临时”栈对象。的在d和最GC语言,这是最常见的,以对堆对象,再有通过一个调用返回时,它具有临时对象复制(或移动)几次没有开销堆 - 因此有没有必要建立一种机制,以避免开销太大。

在d(最GC语言)一class对象从不隐复制你只通过周围的大部分时间基准,所以这个的可以的意思是你不需要任何为他们rvalue引用。

OTOH,struct对象不应该是“句柄资源”,但简单的值类型的行为类似于内建类型 - 如此反复,没有理由在这里的任何移动语义,恕我直言

这将产生一个结论 - d没有右值裁判,因为它并不需要它们

然而在实践中,我没有用右值引用,我只对他们阅读,所以我可能会跳过此功能的一些实际的使用情况。请把这个岗位作为一堆对此问题的想法希望这将是对你有所帮助,而不是作为一个可靠的判断。

我想所有的答案完全没有回答原来的问题。

首先,如上所述,问题是只对结构相关的。类没有意义的举动。上面还指出,对于结构,移动一定量的通过将在一定条件下,编译器自动发生。

如果你希望得到控制的移动操作,这里是你必须做的事情。您可以禁用通过@disable注释本(本)复制。接下来,你可以通过定义constructor(constructor &&that)覆盖C ++的this(Struct that)。同样,你可以重写与opAssign(Struct that)的分配。在这两种情况下,你需要确保你摧毁that的值。

有关任务,因为你还需要摧毁this的旧值,最简单的方法就是交换它们。 C ++的unique_ptr的实现会,因此,看起来像这样:

struct UniquePtr(T) {
    private T* ptr = null;

    @disable this(this); // This disables both copy construction and opAssign

    // The obvious constructor, destructor and accessor
    this(T* ptr) {
        if(ptr !is null)
            this.ptr = ptr;
    }

    ~this() {
        freeMemory(ptr);
    }

    inout(T)* get() inout {
        return ptr;
    }

    // Move operations
    this(UniquePtr!T that) {
        this.ptr = that.ptr;
        that.ptr = null;
    }

    ref UniquePtr!T opAssign(UniquePtr!T that) { // Notice no "ref" on "that"
        swap(this.ptr, that.ptr); // We change it anyways, because it's a temporary
        return this;
    }
}

编辑: 请注意我没有定义opAssign(ref UniquePtr!T that)。这是拷贝赋值运算符,如果你试图去定义它,编译器会报错,因为你宣布,在@disable行,你有没有这样的事情。

我想,如果你需要源宽松,你可能会遇到麻烦的资源。但是作为GC'ed你常常可以避开需要约多的业主担心,因此可能不适合大多数情况下的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top