2013-02-27 51 views
7

我正在使用一個使用std::vector很多的程序。還有很多分配/釋放,其中有數十億分配,我儘量避免儘可能多的分配/釋放。 因爲我對C++比較陌生,所以在使用向量時(例如向它添加元素時),我有幾個關於分配的問題。 我在Win7 64位機器上,程序是32位的,我使用MinGW編譯器的當前版本。何時複製矢量,什麼時候通過了參考?

我想知道,什麼發生在下列情況下,即如果矢量被複制,作爲引用傳遞,...

1.

std::vector<T> fillVector() { 
    std::vector<T> returnVector; 
    ... 
    return returnVector; 
} 

std::vector<T> myVector = fillVector(); 

2.

std::vector<T>& fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return (*returnVector); 
} 

std::vector<T> myVector = fillVector(); 

3.

std::vector<T>* fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return returnVector; 
} 

std::vector<T>* myVector = fillVector(); 

及以下,不同的操作:

4.

std::vector<T> myVector1; 
... (myVector1 being filled) 
std::vector<T> myVector = myVector1; 

5.

std::vector<T>* myVector1 = new std::vector<T>; 
... (myVector1 being filled) 
std::vector<T> myVector = (*myVector1); 

假設我不想改變論點myFunction /變化中myVectormyFunction止跌不傷害節目的其餘部分:

6.

void myFunction(std::vector<T> myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 
void myFunction(std::vector<T>& myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

如果我的理解是正確的,最快的選項(意味着通過引用而不是創建副本,並通過他們的)會是2/3,5和7,請糾正我,如果我錯了!

+1

最快和最乾淨的是選項1. – juanchopanza 2013-02-27 19:09:59

回答

1

最快和最習慣的是選項1.這兩個副本(從returnVector到返回值和從返回值到myVector)幾乎肯定會被編譯器忽略。複製elision是編譯器可能做出的優化,涉及刪除任何不必要的副本。在這裏,這兩個副本都是不必要的,std::vector將直接替代myVector構建。實際上,即使您使用編譯器禁用了複製elision優化,但在C++ 11中,兩個副本實際上都會移動。移動std::vector需要一些分配,並且非常快。第一個被認爲是一個特殊規則的舉動,第二個是移動,因爲表達式fillVector()是一個右值表達式。

+0

這解釋了我做的一些實驗,這對我來說確實沒有意義。 – MrWayne 2013-02-27 19:25:48

7

1.

std::vector<T> fillVector() { 
    std::vector<T> returnVector; 
    ... 
    return returnVector; 
} 

std::vector<T> myVector = fillVector(); 

這是好的。 vector以的值返回,但在(命名的)返回值優化下,大多數編譯器(至少在開啓優化時)將避免對複製構造函數的調用。此外,在C++ 11中,移動語義確保移動構造函數被調用而不是複製構造函數,它將簡單地竊取返回的矢量的內容而不會產生昂貴的副本。

2.

std::vector<T>& fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return (*returnVector); 
} 

std::vector<T> myVector = fillVector(); 

不要這樣做。不必要的動態分配開銷,加上必須記住必須釋放返回對象的負擔。避免手工存儲器管理和偏愛1.

3.

std::vector<T>* fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return returnVector; 
} 

std::vector<T>* myVector = fillVector(); 

同上。避免手動內存管理。

4.

std::vector<T> myVector1; 
... (myVector1 being filled) 
std::vector<T> myVector = myVector1; 

這是一種概念上不同的操作。你在這裏想要來創建一個副本,而且看起來你做得很對。在C++ 11中,如果您只需要傳輸內容myVector1而不是複製它,則可能需要使用std::vector<T> myVector = std::move(myVector1)

5.

std::vector<T>* myVector1 = new std::vector<T>; 
... (myVector1 being filled) 
std::vector<T> myVector = (*myVector1); 

同上,你創建一個副本,但你是不必要的動態分配的載體。這又會迫使你手動處理它的生命週期,這是不好的和容易出錯的。不要這樣做。

6.

void myFunction(std::vector<T> myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

在這裏,你是按值傳遞myVector。是否可以優化取決於什麼myFunction支持它的論點:它會改變它嗎?如果是這樣,你是否希望這些更改從函數返回後可見?如果是的話,傳值是正確的,沒有辦法優化它除非你想搭上myVector對象:在這種情況下,在C++ 11中你可以移動它將它傳遞給函數時。這將避免昂貴的不必要的副本。

7.

void myFunction(std::vector<T>& myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

這將通過引用傳遞,這是隻要OK,因爲它是蠻好看在函數返回後的myFunctionmyVector副作用。一般不能一概而論,這取決於應用程序的特定邏輯。

+0

感謝您的詳細答案。我編輯了我的第一篇關於6和7的文章:讓我們假設在'myFunction'內對'myVector'所做的更改不會損害程序的其餘部分,然後通過引用傳遞肯定會更快,對嗎? – MrWayne 2013-02-27 19:25:06

+0

@MWWayne:在那種情況下,是的。那會更快。如果你將「不會傷害」改變爲「必須被看到」,這也可能是唯一正確的方法。 – 2013-02-27 19:27:05

相關問題