2009-02-24 31 views
4

在C++中,每當一個函數創建了許多(數百或數千個)值,我曾經有過呼叫者傳遞一個數組,我的功能則與輸出值填充:如何從C++函數返回數百個值?

void computeValues(int input, std::vector<int>& output); 

因此,該功能將填補用它計算的值向量output。但是,這並不是很好的C++風格,因爲我現在正在意識到這一點。

下面的函數簽名是更好,因爲它不承諾使用std::vector,但可以使用任何容器:

void computeValues(int input, std::insert_iterator<int> outputInserter); 

現在,調用者可以用一些inserter撥打:

std::vector<int> values; // or could use deque, list, map, ... 
computeValues(input, std::back_inserter(values)); 

再一次,我們不承諾特別使用std::vector,這很好,因爲用戶可能只需要std::set等中的值。(我應該通過值或參考iterator nce?)

我的問題是:insert_iterator是正確還是標準的方法呢?還是有更好的東西?

編輯:我編輯了這個問題,以清楚表明我不是在談論返回兩個或三個值,而是數百或數千。 (想象一下,你有回報所有你在某個目錄中找到的文件,或者在圖形等所有邊)其他

+0

爲什麼不只是函數返回一個std :: vector ?爲什麼它必須是一個「out」參數? – 2009-02-24 22:14:59

+0

如果矢量包含許多值,那麼只是返回它太昂貴。它將在本地創建,並在返回時複製*。我們想避免複製矢量。 – Frank 2009-02-24 22:39:54

回答

7

編輯回覆:好吧,如果您需要如果價值觀返回成千上萬,當然不會成爲一種元素。最好用迭代器挑選解決方案,但最好不要使用任何特定的迭代器類型。


如果你使用迭代器,你應該使用它們儘可能通用。在你的函數中,你使用了一個插入迭代器,如insert_iterator< vector<int> >。你失去了任何通用性。這樣做:

template<typename OutputIterator> 
void computeValues(int input, OutputIterator output) { 
    ... 
} 

無論你給它,它現在會工作。但是如果您在回報集中有不同的類型,它將不起作用。然後你可以使用一個元組。也可作爲std::tuple在下一個C++標準:

boost::tuple<int, bool, char> computeValues(int input) { 
    .... 
} 

如果值的量是可變參數和值的類型是從一組固定的,如(INT,布爾炭),可以尋找到一個容器boost::variant。然而,這意味着僅在呼叫方發生變化。你可以保持迭代器風格的上面:

std::vector< boost::variant<int, bool, char> > data; 
computeValues(42, std::back_inserter(data)); 
1
  • 一個stadard容器爲同質對象9工作,你可以返回)。
  • 標準庫的方法是從容器中提取一個算法,並使用迭代器來彌合之間的差距。
  • 如果您需要通過多個單一類型的思考結構/類。

我的問題是:insert_iterator是否正確或標準的方式來做到這一點?

是。否則,如果您的容器中不會有至少與計算值相同的元素,這並不總是可行的,特別是,如果你想寫入一個流。所以,你很好。

2

如果你有一組對象,機會是你有在該組對象(否則,你跟他們在做什麼?)

的工作至少有幾個方法,如果是這樣的情況下,在包含所述對象和方法的類中包含這些方法是有意義的。

如果這是有道理的,你有這樣的類,返回它。

我幾乎從來沒有發現自己在想我希望我可以返回多個價值。事實上,一個方法只應該做一件小事,你的參數和返回值往往有一定的關係,因此往往不值得一個包含它們的類,所以返回多個值很少有趣(也許我希望在20年內有5次 - 每次我重構,而是取得了更好的結果,並意識到我的第一次嘗試是不符合標準的。)

1

您與insert_iterator例子是行不通的,因爲insert_iterator是需要一個參數一個容器的模板。你可以把它聲明

void computeValues(int input, std::insert_iterator<vector<int> > outputInserter); 

template<class Container> 
void computeValues(int input, std::insert_iterator<Container> outputInserter); 

第一個將配合你回矢量< int>的實施,沒有任何明顯的優勢超過您最初的代碼。第二個限制較少,但作爲模板實施會給你其他限制,可能會使它成爲一個不太理想的選擇。

6

你可以將一個智能指針返回給一個向量。這應該工作,並沒有載體的副本將被製作。

如果您不想爲程序的其餘部分保留智能指針,則可以在調用該函數之前簡單地創建一個向量,然後交換這兩個向量。

1

我會使用類似

std::auto_ptr<std::vector<int> > computeValues(int input); 
{ 
    std::auto_ptr<std::vector<int> > r(new std::vector<int>); 
    r->push_back(...) // Hundreds of these 
    return r; 
} 

在泄漏的回報或風險沒有複製開銷(如果在調用者正確使用auto_ptr)。

3

實際上,你傳入矢量的舊方法有很多推薦它 - 它是高效,可靠和易於理解的。缺點是真實的,但並不適用於所有情況。人們是否真的想要一個std :: set或list中的數據?他們是否真的想要使用數字的長列表而不打擾先將其分配給變量(通過'return'而不​​是參數返回某個原因的原因之一)?通用性很好,但是編程時間有一定的代價,可能不會被兌換。

0

我會說你的新解決方案更通用,更好的風格。我不確定我是否也會擔心關於C++的風格,更多關於可用性和效率。

如果您要返回很多項目並知道大小,使用向量將允許您在一次分配中保留內存,這可能會也可能不值得。