2014-06-26 101 views
2

我研究過C++ 11移動語義,我有這樣一個問題。C++ 11移動語義與C++ 98

例如:

如果我們有一個

vector<T> vt; // also assume that T have pointers on data in separate memory 
vt.push_back(...); 

承擔vt缺乏未使用的容量。然後在C++ 98中,它將爲每個T對象分配更多的內存併爲它們指向的數據複製(調用構造函數副本)。

例如:

T1 - > T1數據=>將被複制t_cop1 - >(t1_cop1數據) T2 - > T2數據=> t_cop2 - >(t2_cop2數據)

C++ 11移動語義允許移動所有T對象(只需複製指針,但不要通過調用移動構造函數將數據複製到單獨的內存中)。我們爲什麼不能在push_back中複製內存(其中包含指針t1,t2,因此t_cop1和t2_cop2將使用相同的指針創建),所以我們不能實現push_back,然後釋放它(t1和t2使用free(void*)爲例)?

UPD:好吧,我會盡量解釋更簡單的例子,我的問題:

舉例來說,如果我們有一個包含一個指向某個數據結構數據的類。 我們實現一個拷貝構造函數是複製指針「數據」

class A { 
public: 
    A() {}; 
    A(const A& a) { 
     data = a.data; 
    } 
private: 
    struct Data{}; 
    Data* data; 
}; 

// And I want to implement "move semantics" by calling the copy constructor (that copies just pointer) 

A* a = new A(); 
A* b(a); 

// and then somehow free "a" object (but not call the destructor) 
free(a); // or a = NULL 

按照我的理解,這就是移動語義幾乎做(但在某種一致的狀態留下)。所以我認爲我們實際上有能力在舊C++中實現移動。不是嗎?

此外,我們可以做在前面的例子一樣用向量

+0

我認爲你誤解了移動語義...... –

+0

這裏沒有區別C++ 11和C++ 98,因爲移動指針時指針只是被複制。另外一個'vector '其中'T'是一個指針,只會圍繞指針移動,而不會指向指針。 – nwp

+0

實際上,但C++ 98將調用深度複製,因此它不僅會複製指針,還會複製指針指向的所有數據。所以問題是爲什麼我們不能實現移動語義的C++ 98 – Nikita

回答

0

「移動語義」提供編譯器將像構造函數的東西,可以分化爲左值引用引用的方式(你的那種」在C++ 98中找到)和右值引用(新增C++ 11,使用&&表示法,它們指的是臨時和中間對象,並且可能不會超過當前語句)。

所以,現在我們可以編寫一個拷貝構造函數(「使新對象成爲這個拷貝的副本」)和一個不同的移動構造函數(「使新對象成爲這個拷貝的一個副本,並且通過源對象是一個臨時的,將在下一個被銷燬,所以如果你想以不會離開源對象完整的方式進行優化,請繼續「)。因此,例如,在容器類中,可以使用複製構造函數複製容器類,並且新副本將包含其所有內容的完整副本(這意味着像元素一樣的複製構造內容將會發生)。但移動構造函數可以跳過所有這些工作,只需將內部元素與源容器交換即可,只需接管源容器的內容並將源容器留空即可。 (後來源容器被破壞,這應該是微不足道的,因爲它是空的。)通常可以在恆定的時間內完成,而不是O(N)或更糟。

在C++ 98中,您不能使用等效的作爲構造函數(並因此使用臨時對象),因爲它只知道如何創建副本。有一種方法可以通過swap()函數(和某些類中的方法)實現類似的效果,但必須明確寫入。 (基本上,容器a的內容移動到新構建的空容器b,可調用swap(a, b);,然後破壞a然後這將是空的。)的情況下的


一個例子,你只可以」噸做正確的事在C++ 98初始化向量與函數的返回一個向量的結果:

vector<int> fibonacci(int n) { 
    vector<int> result; 
    if(n <= 0) return result; 
    result.push_back(0); 
    if(n <= 1) return result; 
    result.push_back(1); 
    for(int i = 1; i < n; ++i) 
     result.push_back(result[i] + result[i - 1]); 
    return result; 
} 

vector<int> datavect = fibonacci(10); 

C++ 98和C++ 11都將遠離的Elid函數返回複製(在存儲返回值的位置創建result)但C++ 98可以o因爲沒有移動語義,所以只能調用datavect的拷貝構造函數。 C++ 11可以調用移動構造函數,它可以將存儲從臨時返回值移動到datavect。沒有真正的方法來在C++ 98中執行此操作,而不涉及operator newoperator delete,並且返回指針而不是對象,從而在(非確定性時間)免費存儲區上跳動以獲得增益。

+0

是的,這就是移動語義所做的。所以我的問題是如何(或爲什麼不)我們不能在C++ 98中實現移動語義? – Nikita

+0

看我的最後一段。簡而言之:你必須手動完成,而且在某些情況下不能完成它,比如返回容器的函數(而不是指針或引用)。 –

+0

是的,我同意在交換和斐波納契舊C++的情況下是不合適的。但在我的例子中(並且也有向量),可以通過模擬移動語義來提高性能。那麼爲什麼他們沒有在C++ 11之前的stl中實現呢? – Nikita