使用外部資源(如std::vector<T>
或std::string
)的「值類型」問題是複製它們往往非常昂貴,並且副本是在各種上下文中隱式創建的,因此這往往是性能問題。 C++ 0x對此問題的回答是移動語義,這概念性地基於資源竊取的思想,並且技術上由右值引用支持。確實d必須的C++ 0x的移動語義類似的東西?
確實d有類似的東西移動語義或右值引用?
使用外部資源(如std::vector<T>
或std::string
)的「值類型」問題是複製它們往往非常昂貴,並且副本是在各種上下文中隱式創建的,因此這往往是性能問題。 C++ 0x對此問題的回答是移動語義,這概念性地基於資源竊取的思想,並且技術上由右值引用支持。確實d必須的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++一樣提升性能嗎?從本質上講,這似乎不太可能。
我知道'struct'和'class'之間的區別。我想知道如果我可以用移動語義設計一個'struct' :) – fredoverflow 2010-11-16 23:55:05
哦,我明白了,你想要一個更精確的答案。那麼我就得檢查一下,或者等待更好的答案。 – Klaim 2010-11-16 23:55:58
'struct'沒有完整的值語義(這意味着不變性),它只是傳遞值。 – 2016-04-01 07:11:29
我總覺得右值實際上引用了「移動語義」的整個概念,這是C++創建本地「臨時」堆棧對象時的正常結果。 在d和大多數GC的語言,這是最常見的有上堆物,然後有與具有臨時對象複製(或移動)通過調用堆棧返回時,幾次沒有開銷 - 因此沒有必要對機制也可以避免這種開銷。
在d(最GC語言)一class
對象從不隱複製你只繞過大部分時間基準,因此這可能意味着你不需要他們的任何右值引用。恕我直言,恕我直言,沒有任何移動語義的理由,恕我直言,這裏沒有任何移動語義的理由。
這將得出一個結論 - D沒有右值參考因爲它不需要它們。
但是,我在實踐中沒有使用右值引用,我只讀過它們,所以我可能跳過了這個特性的一些實際用例。請把這個崗位作爲一堆對此問題的想法希望這將是有益的你,而不是作爲一個可靠的判斷。
用這個邏輯,你也可以說C++不需要右值引用,因爲有shared_ptrs。 – 2011-03-11 13:18:30
我認爲如果您需要源代碼來釋放您可能遇到麻煩的資源。不過,通過GC,您可以避免需要擔心多個所有者,因此在大多數情況下它可能不是問題。
我認爲所有的答案完全無法回答原來的問題。
首先,如上所述,這個問題只與結構有關。班級沒有有意義的舉動。上面還指出,對於結構體來說,編譯器在特定條件下會自動發生一定程度的移動。
如果你想控制移動操作,這是你必須做的。您可以通過使用@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
行中聲明瞭您沒有這種東西。
您的代碼正在這裏討論的情況下,你有興趣http://forum.dlang.org/post/[email protected] – 2016-01-31 20:36:56
是不是一個D2特定的東西?我認爲這很好,可以澄清我們現在討論的D版本是什麼:) – Kos 2010-11-17 10:37:48
@Kos我不知道D1做了什麼,也沒有。我只使用D2,並且通常假設D中的問題與D2相關,除非另有說明 - 特別是當問題似乎來自不是D用戶的人,並且甚至可能不知道存在版本1和版本時2的語言。我只是將術語D表示爲語言的當前版本。 – 2010-11-17 17:31:13
但是D2是...呃,上次我檢查C++ 0x-ish時,即規範改變了所有的時間,並且編譯器的支持都是「實驗性的」。這使我得出結論,應該說明他是在談論穩定或實驗版本還是語言。或者,也許D2終於穩定了?我不上最新與d :-) – Kos 2010-11-17 18:20:18