簡體   English   中英

包含引用或指針的對象向量

[英]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對象。 該對象現在駐留在從0x12340x123C的存儲器塊中。 成員變量var位於0x1234 ,成員變量ref位於0x1238 對於此對象, var的值為0x0005ref的值為0x1234

在向量中添加元素時,向量在第二次插入期間用完了空間。 因此,它調整大小並將當前元素(此時只是第一個元素)從位置0x1234到位置0x2000 這意味着成員元素也移動了,因此var現在位於地址0x2000ref現在位於0x2004 但是它們的值被復制了,因此var的值仍然是0x0005 ,而ref的值仍然是0x1234

ref指向一個無效的位置(但var仍然包含正確的值!)。 嘗試訪問內存引用現在指向未定義的行為,通常是壞的。

這樣的事情將是一種更典型的方法來提供對成員屬性的引用訪問:

int & get_ref() {return var;}

將引用作為成員屬性本身並沒有 ,但如果要存儲對象的引用,則必須確保該對象不會移動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM