2012-07-06 96 views
0

出於某種原因,我想返回my :: Vector的對象(這基本上是一個包裝類,內部使用STL向量用於實際存儲,並提供一些額外的功能) 。隨着函數每次在本地創建一個向量,我會按值返回向量。通過C++中的多重函數嵌套值返回向量

my::Vector<int> calcOnCPU() 
{ 
    my::Vector<int> v.... 
    return v; 
} 

現在我可以有函數調用(考慮庫設計)多重嵌套,因此,在短期類似如下:

my::Vector<int> calc() 
{ 
    if(...) 
     return calcOnCPU(); 
} 

據我所知,通過價值迴歸將調用我的::拷貝構造函數Vector類這是一件好事:

Vector<int>::Vector(const Vector& c) 
{ 
    .... 
    m_vec = c.m_vec; // where m_vec is std::vector<int> 
} 

幾個問題: 1)在拷貝構造函數,它被調用的std ::載體的拷貝構造函數?或賦值運算符,只需確認,std :: vector創建深度複製(意味着複製考慮基本整數類型的所有元素)。 2)在Calc()中嵌套calcOnCPU(),每個都返回int的Vector:2或1個Vector的拷貝將被創建?如果這種簡單的方法嵌套,我怎麼能避免多個副本?內聯函數還是存在另一種方式?

UPDATE 1:對我來說很明顯我需要保留我自己的拷貝構造函數,因爲有一些自定義需求。但是,我做了一個簡單的測試,主要功能:

int main() { 
    ... 
    my::Vector v = calc(); 
    std::cout<<v; 
} 

我把一些印刷用我的拷貝構造函數「的std :: CERR」時看到它被調用。有趣的是,上面的程序甚至不會調用它(至少不會打印)。是否複製橢圓優化?我在Linux上使用GNU C++編譯器(g ++)v4.6.3。

+0

即將推出的(當前?)C++標準中有「移動語義」。是的,STL向量執行深層複製,這就是你的代碼 – fork0 2012-07-06 12:47:37

+0

[Rvalue引用和移動構造函數](http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors) – fork0 2012-07-06 12:49:07

+0

如果你試圖擺脫臨時副本,也許你可以讓每個嵌套函數爲你的向量引用一個引用參數,你修改... – 2012-07-06 12:51:04

回答

2

在拷貝構造函數中,它調用std :: vector的拷貝構造函數嗎?或轉讓運營商

在你的情況,它創建一個空的std::vector,然後複製分配它。使用初始化器列表將直接複製構造它,這是整潔,可能更有效:

Vector<int>::Vector(const Vector& c) : m_vec(c.m_vec) { 
    .... 
} 

只是爲了確認,性病::向量創建深拷貝

是,複製std::vector將分配一個新的內存塊並將所有元素複製到該內存中。

在calc()中嵌套calcOnCPU(),每個都返回int向量Vector:2或1個Vector的拷貝將被創建?

這取決於編譯器。它應該應用「返回值優化」(複製elision的一個特例),在這種情況下,它不會創建一個本地對象並返回一個副本,但會直接在分配給返回的空間中創建它目的。例如,有些情況下無法完成 - 例如,如果有多個返回語句可能返回多個本地對象之一。

此外,一個現代編譯器也將支持移動語義哪裏,即使副本不能被消除,矢量的內容將被移動到返回的對象,而不是複製;也就是說,它們將通過設置向量的內部指針來快速傳輸,而不需要分配內存或複製元素。然而,既然你在自己的類中包裝矢量,並且你已經聲明瞭一個拷貝構造函數,那麼你必須給這個類一個移動構造函數,以便它能夠工作 - 只有當你使用C++ 11。

如何在這種簡單方法嵌套的情況下避免多個副本?內聯函數還是存在另一種方式?

確保您的函數的結構足夠簡單,以便複製elision工作。如果可以的話,給你的類一個移動構造函數來移動向量(或者移除複製構造函數,如果存在,則賦值運算符允許隱式生成)。內聯不太可能有所作爲。

+0

感謝您的回答。一個關於「或刪除複製構造函數以允許隱式生成」的說明「如果刪除我的複製構造函數會發生什麼?隱式生成的拷貝構造函數可以做什麼不同? – usman 2012-07-06 13:11:18

+2

@ user600029:這不是隱式定義的複製構造函數可以做的事情,而是你在聲明自己的時候禁止編譯器執行的操作。特別是,如果可能,編譯器(C++ 11)將提供一個移動構造函數,但如果您提供了一個拷貝構造函數(或賦值運算符...),它將不會這樣做。也就是說,通過不提供禁止生成移動構造函數的操作之一,您可以免費獲得性能提升(或者如果您仍在使用C++ 03,則更新編譯器) – 2012-07-06 13:17:56

+0

@ user600029:如果您刪除你的拷貝構造函數,然後隱式的將複製每個對象成員 - 在很多情況下,這正是你想要的。如果你刪除它(和賦值運算符,並且不聲明你自己的移動構造函數或移動賦值運算符),那麼編譯器也會給你一個移動構造函數。 – 2012-07-06 13:20:58