2010-11-16 23 views
28

使用外部資源(如std::vector<T>std::string)的「值類型」問題是複製它們往往非常昂貴,並且副本是在各種上下文中隱式創建的,因此這往往是性能問題。 C++ 0x對此問題的回答是移動語義,這概念性地基於資源竊取的思想,並且技術上由右值引用支持。確實d必須的C++ 0x的移動語義類似的東西?

確實d有類似的東西移動語義或右值引用?

回答

25

我相信在D中有幾個地方(例如返回結構),D設法使它們移動,而C++會使它們成爲副本。 IIRC,編譯器會在確定不需要副本的情況下進行移動而不是複製,所以結構複製在D中比在C++中發生得更少。當然,由於課程是參考資料,它們根本就沒有問題。

但不管如何,複製構造在D中的工作方式與在C++中的工作方式不同。通常,不是聲明一個拷貝構造函數,而是聲明一個postblit構造函數:this(this)。它在調用this(this)之前完成了一個完整的memcpy,並且只需進行必要的更改以確保新結構與原始結構是分離的(例如在需要時對成員變量進行深層複製),而不是創建全新的結構必須複製一切的構造函數。所以,一般的方法已經與C++有所不同了。人們還普遍認爲,結構不應該有昂貴的postblit構造函數 - 複製結構應該便宜 - 所以它不像C++那樣是一個問題。對於複製而言昂貴的對象通常是具有引用或COW語義的類或結構。因爲它們不需要多態性,但是複製它們不會複製它們的內容,所以它們仍然是引用類型),因此將它們複製到其中周圍並不像C++那樣昂貴。

在D中可能會使用類似於移動構造函數的情況,但通常情況下,D的設計方式可以減少C++在複製對象時遇到的問題,所以它是遠不及C++中存在的問題。

+0

是不是一個D2特定的東西?我認爲這很好,可以澄清我們現在討論的D版本是什麼:) – Kos 2010-11-17 10:37:48

+6

@Kos我不知道D1做了什麼,也沒有。我只使用D2,並且通常假設D中的問題與D2相關,除非另有說明 - 特別是當問題似乎來自不是D用戶的人,並且甚至可能不知道存在版本1和版本時2的語言。我只是將術語D表示爲語言的當前版本。 – 2010-11-17 17:31:13

+0

但是D2是...呃,上次我檢查C++ 0x-ish時,即規範改變了所有的時間,並且編譯器的支持都是「實驗性的」。這使我得出結論,應該說明他是在談論穩定或實驗版本還是語言。或者,也許D2終於穩定了?我不上最新與d :-) – Kos 2010-11-17 18:20:18

1

d具有獨立的價值和目標的語義:

  • 如果你聲明的類型struct,它會值默認爲
  • 語義,如果你宣佈你的類型class,就會有對象的語義。

現在,假設你不親自管理內存,因爲它是在d默認情況下 - 使用垃圾收集器 - 你要明白的聲明爲class類型的對象自動爲指針(或「參考」如果你更喜歡)真實的物體,而不是真實的物體本身。

所以,當在D中傳遞向量時,你傳遞的是參考/指針。自動。沒有涉及的副本(除參考副本外)。這就是爲什麼D,C#,Java和其他語言不需要「移動」語義(因爲大多數類型是對象語義,並且通過引用而不是通過複製來操縱)。

也許他們可以實現它,我不知道。但是他們真的會像C++一樣提升性能嗎?從本質上講,這似乎不太可能。

+1

我知道'struct'和'class'之間的區別。我想知道如果我可以用移動語義設計一個'struct' :) – fredoverflow 2010-11-16 23:55:05

+0

哦,我明白了,你想要一個更精確的答案。那麼我就得檢查一下,或者等待更好的答案。 – Klaim 2010-11-16 23:55:58

+1

'struct'沒有完整的值語義(這意味着不變性),它只是傳遞值。 – 2016-04-01 07:11:29

1

我總覺得右值實際上引用了「移動語義」的整個概念,這是C++創建本地「臨時」堆棧對象時的正常結果。 在d和大多數GC的語言,這是最常見的有上堆物,然後有與具有臨時對象複製(或移動)通過調用堆棧返回時,幾次沒有開銷 - 因此沒有必要對機制也可以避免這種開銷。

在d(最GC語言)一class對象從不隱複製你只繞過大部分時間基準,因此這可能意味着你不需要他們的任何右值引用。恕我直言,恕我直言,沒有任何移動語義的理由,恕我直言,這裏沒有任何移動語義的理由。

這將得出一個結論 - D沒有右值參考因爲它不需要它們

但是,我在實踐中沒有使用右值引用,我只讀過它們,所以我可能跳過了這個特性的一些實際用例。請把這個崗位作爲一堆對此問題的想法希望這將是有益的你,而不是作爲一個可靠的判斷。

+5

用這個邏輯,你也可以說C++不需要右值引用,因爲有shared_ptrs。 – 2011-03-11 13:18:30

0

我認爲如果您需要源代碼來釋放您可能遇到麻煩的資源。不過,通過GC,您可以避免需要擔心多個所有者,因此在大多數情況下它可能不是問題。

1

我認爲所有的答案完全無法回答原來的問題。

首先,如上所述,這個問題只與結構有關。班級沒有有意義的舉動。上面還指出,對於結構體來說,編譯器在特定條件下會自動發生一定程度的移動。

如果你想控制移動操作,這是你必須做的。您可以通過使用@disable註釋此(this)來禁用複製。接下來,您可以通過定義this(Struct that)來覆蓋C++的constructor(constructor &&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行中聲明瞭您沒有這種東西。

+0

您的代碼正在這裏討論的情況下,你有興趣http://forum.dlang.org/post/[email protected] – 2016-01-31 20:36:56

相關問題