2012-04-18 40 views
11

我試圖插入現有的vector元素的副本來將其加倍。下面的代碼曾在以前的版本中,但在Visual Studio 2010失敗如何將重複元素插入到矢量中?

#include <iostream> 
#include <vector> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    vector<int> test; 
    test.push_back(1); 
    test.push_back(2); 
    test.insert(test.begin(), test[0]); 
    cout << test[0] << " " << test[1] << " " << test[2] << endl; 
    return 0; 
} 

輸出是-17891602 1 2,預計1 1 2

我已經知道爲什麼會發生這種情況 - 矢量正在被重新分配,並且在複製到插入點之前引用變爲無效。較早的Visual Studio顯然是以不同的順序做了事情,從而證明未定義行爲的一個可能結果是正確工作,並且證明它絕不是你應該依賴的東西。

我想出了兩種不同的方法來解決這個問題。一種是使用reserve以確保沒有重新分配發生:

test.reserve(test.size() + 1); 
    test.insert(test.begin(), test[0]); 

另一種是使從參考副本,以便有一個在參考其餘沒有依賴有效:

template<typename T> 
T make_copy(const T & original) 
{ 
    return original; 
} 

    test.insert(test.begin(), make_copy(test[0])); 

雖然既工作,也沒有人覺得自然的解決方案。有什麼我失蹤?

+0

BTW vc11 dev預覽給出了第一個例子中的'1 1 2'。 – 2012-04-18 21:28:54

+0

@Jesse,這並不讓我感到意外。正在選擇'insert'的Rvalue重載,這看起來像是他們可能已經修復的錯誤。該代碼在超載和採用const引用的代碼之間完全不同。 – 2012-04-18 21:32:24

+0

是否投射到int工作? – 2012-04-18 21:35:50

回答

1

我相信這是定義的行爲。在2011年C++標準的§23.2.3中,表100列出了序列容器要求,並且存在這種情況的條目。它給出了示例表達

a.insert(p,t) 

其中aX一個值,它是含有T類型的元素的序列容器類型,p是一個常量迭代到a,和tX::value_type類型的左值或const右值,即T

此表達的斷言是:

需要:TCopyInsertableX。對於vectordeque,T也應該是CopyAssignable
影響:p之前插入t的副本。

唯一相關的載體具體報價,我能找到在§23.3.6.5第1款:

注:導致重新分配,如果新的尺寸比舊款更大的容量。如果沒有重新分配,插入點之前的所有迭代器和引用仍然有效。

雖然這確實提到了重新分配的向量,但它並不是例外,以前的需求序列容器上的insert

至於解決這個問題,我同意@ EdChum的建議只是製作一個元素的副本並插入該副本。

+0

我在你的描述中沒有看到任何東西在調用't'是對'a'成員的引用。 – 2012-04-19 01:52:35

4

問題是vector::insert將一個值作爲第二個參數而不是一個值的引用。您不需要模板來創建副本,只需使用副本構造函數來創建另一個對象,該對象將通過引用傳遞。即使矢量調整大小,該副本仍然有效。

#include <iostream> 
#include <vector> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    vector<int> test; 
    test.push_back(1); 
    test.push_back(2); 
    test.insert(test.begin(), int(test[0])); 
    cout << test[0] << " " << test[1] << " " << test[2] << endl; 
    return 0; 
} 
+0

這只是一個測試案例。我的實際代碼包含比int更復雜的元素,而臨時構造函數只會變得很難看。好的建議,但。 – 2012-04-20 04:24:03