[英]Vector of objects containing references or pointers
我將一些對象存儲在向量中。 當我調用這樣一個使用引用的對象的成員函數時,程序終止(沒有錯誤)。 我寫了下面的代碼做了一些測試。 它在添加元素之后接縫,第一個條目中的引用失敗。 為什么這樣做,我該怎么做才能避免這個問題呢? 當我使用指針而不是引用時,它的行為完全相同。
#include <iostream>
#include <vector>
using namespace std;
class A{
public:
A(int i) : var(i), ref(var) {}
int get_var() {return var;}
int get_ref() {return ref;}
private:
int var;
int& ref;
};
int main ()
{
vector<A> v;
for(unsigned int i=0;i<=2 ;i++){
v.emplace_back(i+5);
cout<<"entry "<<i<<":"<<endl;
cout<<" var="<<v.at(i).get_var()<<endl;
cout<<" ref="<<v.at(i).get_ref()<<endl;
}
cout<<endl;
for(unsigned int i=0;i<=2 ;i++){
cout<<"entry "<<i<<":"<<endl;
cout<<" var="<<v.at(i).get_var()<<endl;
cout<<" ref="<<v.at(i).get_ref()<<endl;
}
return 0;
}
輸出是:
entry 0:
var=5
ref=5
entry 1:
var=6
ref=6
entry 2:
var=7
ref=7
entry 0:
var=5
ref=0 /////////////here it happens!
entry 1:
var=6
ref=6
entry 2:
var=7
ref=7
v has 3 entries
這是因為你對emplace_back的調用導致向量調整大小。 為了做到這一點,向量可能必須或可能不必將整個向量移動到存儲器中的不同位置。 您的“ref”仍然引用舊的內存位置。
這實際上是否發生在某種程度上依賴於實現; 編譯器可以自由地為向量保留額外的內存,這樣他們就不必在每次向后面添加內容時重新分配。
它在emplace_back的標准文檔中提到 :
迭代器有效性
如果發生重新分配,則與此容器相關的所有迭代器,指針和引用都將失效。 否則,只有結束迭代器失效,並且所有其他迭代器,指針和對元素的引用都保證在調用之前引用它們所引用的相同元素。
為了避免這個問題,您可以(如評論中的JAB建議)動態創建引用,而不是將其存儲為成員變量:
int& get_ref() {return var;}
...雖然我寧願使用智能指針而不是這種東西。
或者,正如RnMss建議的那樣,實現復制構造函數,以便每當向量復制對象時它都引用新位置:
A(A const& other) : ref(var) {
*this = other;
}
好的,所以這里發生了什么。 根據內存位置來理解對象真的很有幫助,並且記住允許向量在內存中移動對象。
v.emplace_back(5)
您在向量中創建一個A對象。 該對象現在駐留在從0x1234
到0x123C
的存儲器塊中。 成員變量var位於0x1234
,成員變量ref位於0x1238
。 對於此對象, var的值為0x0005
, ref的值為0x1234
。
在向量中添加元素時,向量在第二次插入期間用完了空間。 因此,它調整大小並將當前元素(此時只是第一個元素)從位置0x1234
到位置0x2000
。 這意味着成員元素也移動了,因此var現在位於地址0x2000
, ref現在位於0x2004
。 但是它們的值被復制了,因此var的值仍然是0x0005
,而ref的值仍然是0x1234
。
ref指向一個無效的位置(但var仍然包含正確的值!)。 嘗試訪問內存引用現在指向未定義的行為,通常是壞的。
這樣的事情將是一種更典型的方法來提供對成員屬性的引用訪問:
int & get_ref() {return var;}
將引用作為成員屬性本身並沒有錯 ,但如果要存儲對象的引用,則必須確保該對象不會移動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.