2010-09-13 65 views
10

可能重複:
how to 「return an object」 in C++C++向量,返回與參數

我想知道如果有下列三種方法之間的差異:

void FillVector_1(vector<int>& v) { 
    v.push_back(1); // lots of push_backs! 
} 

vector<int> FillVector_2() { 
    vector<int> v; 
    v.push_back(1); // lots of push_backs! 
    return v; 
} 

vector<int> FillVector_3() { 
    int tab[SZ] = { 1, 2, 3, /*...*/ }; 
    return vector<int>(tab, tab + SZ); 
} 
+1

表現如何? – Anycorn 2010-09-13 18:33:08

+4

當你覺得它實際上是一個問題時,只要回報價值並擔心表現。然後對其進行配置,以便您不必猜測。我搶先成爲[重複](http://stackoverflow.com/questions/3350385/how-to-return-an-object-in-c)。 – GManNickG 2010-09-13 18:34:23

+1

我不會因爲幾個原因投票決定將其作爲一個副本來關閉它:(1)前面的問題有關於動態內存分配的細節不適用於這個問題,(2)這個問題是STL特定的,它可以調用其他成語,如插入迭代器。此外,STL的某些實現已經利用C++ 0x r值引用來最大限度地減少複製。該方法不適用於前面的問題。 – 2010-09-13 19:16:47

回答

16

最大的區別在於第一種方式附加到現有內容,而另外兩種填充空向量。 :)

我認爲你正在尋找的關鍵字是return value optimization,這應該是相當普遍的(與G ++,你必須關掉它,專門以防止它被應用)。也就是說,如果用法如下:

vector<int> vec = fill_vector(); 

然後可能很容易沒有複製(而功能更容易使用)。

如果您正在使用現有矢量

vector<int> vec; 
while (something) 
{ 
    vec = fill_vector(); 
    //do things 
} 

工作然後使用out參數將避免圍繞在一個循環的載體和複製數據的創建。

+1

+1用於指出初始化和賦值w.r.t之間的區別。複製elision。 – sellibitze 2010-09-13 18:45:25

2

的首先肯定不復制矢量。

複製向量的成本可能與向量中元素的數量成線性關係。

第一個沒有在任何平臺或編譯器中引入線性行爲的風險,也沒有分析和重構的成本。

+0

第一個也允許在一行中調用幾個函數來填充單個向量。如果你需要對#2做同樣的事情,你必須從被返回的向量中複製元素(這意味着編譯器所做的所有英雄RVO的努力都是徒勞的,因爲你最終會得到一個立即可用的結果,無論如何丟棄的副本)。 – 2010-09-13 19:01:24

6

人們會假設參數是最好的,但實際上它通常不是。這取決於編譯器。一些編譯器(我認爲實際上是最新編譯器)將適用Return Value Optimization - Visual Studio 2005和更高版本應該在您提供的兩種情況下執行此操作(請參閱Named Return Value Optimization in Visual C++ 2005)。

確切知道的最好方法是檢查產生的反彙編。

+0

這是一個_huge_優化,大多數現代編譯器都在性能方面取得很大的收益。 – fbrereto 2010-09-13 18:38:08

+0

RVO的整個想法讓我感到畏縮。我討厭它。 – 2010-09-13 19:28:53

0

乍看之下,前兩個可能會更多地調整矢量的大小,而第三個可能無需在矢量運行時調整它的大小。這可以通過在推送前自己調整大小來緩解。

5

將第四個變體進入混合:

void FillVector_4(vector<int>& v) { 
    static const int tab[SZ] = {1,2,3, ... }; 
    v.assign(tab,tab+SZ); 
} 

如果你想表現第2版和第3版可以使編譯器創建一個vector<int>副本的返回值。也就是說,如果編譯器不能夠執行NRVO(命名返回值優化)。此外,連續的push_back s沒有reserve可能會導致一些重新分配,因爲矢量需要增長。這是否完全取決於你想要解決的問題。

您會很高興知道C++ 0x將使返回本地創建的矢量非常高效。我還建議閱讀David Abrahams article series瞭解有效價值類型,包括傳遞/返回。

9

的慣用C++方法將是抽象在容器類型通過使用輸出迭代:

std::vector<int> v; 
FillContainer(std::back_inserter(v)); 

性能(和其他:

template<typename OutputIterator> 
void FillContainer(OutputIterator it) { 
    *it++ = 1; 
    ... 
} 

然後,它可與載體一起使用諸如能夠填充非空容器的優點)與您的選項#1相同。另一件好事是,如果使用適當類型的迭代器(例如ostream_iterator),則可以以流模式輸出結果,其中結果立即被處理並丟棄而不被存儲。

+0

+1。這似乎是最「STL方式」。請注意,從'FillContainer'返回迭代器可能很有用。 – 2010-09-13 19:19:53

+0

當「FillContainer」是一個類的方法時,這是如何工作的? – User 2011-05-24 00:07:25

+0

@User:同樣的方式 - 類成員函數也可以模板化。你不能用這樣的東西做的事情是虛擬的。 – 2011-05-24 16:57:08