2015-06-30 90 views
3

爲什麼這麼多的電話複製缺點,我只希望只有最後九個?甚至根本不會返回價值優化。爲什麼這麼多的複製,而轉換/複製矢量

struct C 
{ 
    int _i; 
    C(int i) : _i(i) {} 
    C(const C& other) { cout << "copy cons from " << other._i << " to " << _i << endl; _i = other._i; } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    vector<int> vi{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
    vector<C> vc; 
    transform(vi.begin(), vi.end(), back_inserter(vc), 
     [](int i) 
    { 
     return C(i); 
    }); 
} 

輸出:

copy cons from 1 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 4 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 4 to - 842150451 
copy cons from 5 to - 842150451 
copy cons from 6 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 4 to - 842150451 
copy cons from 5 to - 842150451 
copy cons from 6 to - 842150451 
copy cons from 7 to - 842150451 
copy cons from 8 to - 842150451 
copy cons from 9 to - 842150451 

回答

10

您的載體vc有增長几十倍。每次它都會分配一個更大的內存塊,並複製原始元素。

您可以通過使用std::vector::reserve預留足夠的空間來阻止它的發生。

vector<C> vc; 
vc.reserve(vi.size()); 
+1

謝謝,這是真的,但爲什麼它增長得如此緩慢,但沒有例如。每次兩倍?這不是很傻嗎? – Yola

+3

@Yola它靠近兩個因子增長。確切的因素取決於實施。 – juanchopanza

+0

許多實現使用接近黃金比例(〜1.62)的增長因子而不是2的主要原因是這可以防止內存碎片。請參閱[本答案](http://stackoverflow.com/a/1100426/358277)以獲得更深入的解釋 –

4

如從程序的輸出觀察時一個新元素被添加到該載體然後重新分配內存和已經載體的存在元素在新的地點被複制。

在運行避免內存重新分配的算法之前,您可以保留足夠的內存。

vector<C> vc; 
vc.reserve(vi.size()); 

在這種情況下,可以避免複製構造函數的重複調用。

但它不是完整的故事。:)

C類具有轉換構造

C(int i) : _i(i) {} 

它允許通過替換算法std::transform使用的呼叫簡化創建矢量vc的元素算法std::copy的lambda表達式不使用lambda表達式。例如

std::copy(vi.begin(), vi.end(), std::back_inserter(vc)); 

但是,即使這不是完整的故事:)

當您使用std::transformstd::copy再就是使用兩個構造函數:一個參數和拷貝construtor構造。

您可以避免使用複製建築師並實現更高效的結果。簡單地代替方法push_back最好使用方法emplace_back

如何使用這種方法?

最簡單的一種是使用範圍爲基礎的聲明

for (int x : vi) vc.emplace_back(x); 

這是不夠清晰可讀。

如果你想使用一個標準的算法,你可以寫

std::for_each(vi.begin(), vi.end(), [&vc](int x) { vc.emplace_back(x); }); 

在這兩種情況下只有一個參數構造函數將被調用,避免調用拷貝構造函數。

自己檢查一下。:)

+0

謝謝您的詳細解答。 – Yola

+1

@Yola我希望這是一個有趣和有用的答案。:) –