2015-08-19 85 views
0

我想要創建一個對象,將該對象放入vector,並且仍然能夠通過僅訪問vector來修改同一個對象。但是,我知道當一個對象是push_back()vector時,該對象實際上被複制到vector。因此,訪問vector中的對象將僅訪問一個類似但不同的對象。僅使用標準庫創建「矢量矢量」的標準操作

我有一個初學者在C知識,讓我知道我可以創建一個指向對象的指針,使指針的載體。例如vector<Object *>。但是,似乎pointers是C++中的discouraged,以及references are preferred。然而,I cannot make a vector of references

我希望只使用標準庫,所以boost是關閉的限制我。

我聽說過智能指針。但是,它看起來好像有多種類型的智能指針。這對於這個目的不會過分嗎?如果智能指針確實是答案,那麼我該如何確定使用哪一個?

所以我的問題是:什麼是用於創建引用/指針到對象的矢量標準的做法?

換句話說,希望下面(僞)代碼工作。

#include <iostream> 
#include <cstdlib> 
#include <vector> 

using namespace std; 

class Object 
{ 
public: 
    int field; 
}; 

vector<Object> addToVector(Object &o) 
{ 
    vector<Object> v; 
    v.push_back(o); 
    v[0].field = 3; // I want this to set o.field to 3. 

    return v; 
} 

int main() 
{ 
    Object one; 
    one.field = 1; 
    cout << one.field << endl; // 1 as expected 

    Object &refone = one; 
    refone.field = 2; 
    cout << one.field << endl; // 2 as expected 

    vector<Object> v = addToVector(one); 

    cout << v[0].field << endl; // 3 as expected 

    cout << one.field << endl; // I want to get 3 here as well, as opposed to 2. 


    return 0; 
} 
+0

只要向量不需要擔心它們指向的對象的生命週期,指針向量就沒有問題。 – juanchopanza

+0

改用智能指針向量。我很確定這個問題是重複的。 –

+0

對不起,如果它是重複的。我發現的唯一一個類似於我的問題提出了使用boost,我希望避免。如果這確實是重複的,請讓我知道。 – Zsw

回答

1

我想創建一個對象,把對象變成一個載體,並且仍然能夠通過訪問只有矢量修改同一個對象。但是,我知道當一個對象是push_back()對一個向量時,該對象實際上被複制到向量中。因此,訪問向量中的對象只會訪問類似但不同的對象。

我幾乎可以肯定,這不是你想要或「應該」想要的。原諒我直接打開我的答案,但除非你有充分的理由這樣做,否則你可能不想這樣做。

對於這個 - 帶引用的矢量 - 爲了您的工作必須保證在引用它們時引用的對象不會被移動也不會被破壞。如果你有一個矢量,確保矢量不被調整大小。如果像你的例子那樣將它們放在堆棧中,那麼不要讓引用的向量或其副本離開該堆棧幀。如果你想將它們存儲在某個容器中,請使用std::list(它是迭代器 - 基本上指針 - 在插入或移除元素時不會失效)。

你已經注意到了,你不能有「真正的」參考向量。原因是因爲引用是不可分配的。請考慮下面的代碼:

int a = 42; 
int b = 21; 
int & x = a; // initialisation only way to bind to something 
int & y = b; 
x = y; 
b = 0; 

之後,你從x獲得的值將是21,因爲轉讓並沒有改變引用(綁定到b),但引用的對象,a。但一個std::vector explicitly requires這。

現在,您可以設置出和寫入周圍像一個指針的包裝...

template<typename T> 
struct my_ref { 
    T * target; 
    // don't let one construct a my_ref without valid object to reference to 
    my_ref(T & t) : target(&t) {} 
    // implicit conversion into an real reference 
    operator T &(void) { 
    return *target; 
    } 
    // default assignment works as expected with pointers 
    my_ref & operator=(my_ref const &) = default; 
    // a moved from reference doesn't make sense, it would be invalid 
    my_ref & operator=(my_ref &&) = delete; 
    my_ref(my_ref &&) = delete; 
    // ... 
}; 

...但是這是非常沒有意義的,因爲std::reference_wrapper已經提供正是:

int main (int, char**) { 
    int object = 21; // half of the answer 
    vector<reference_wrapper<int>> v; 
    v.push_back(object); 
    v[0].get() = 42; // assignment needs explicit conversion of lhs to a real reference 
    cout << "the answer is " << object << endl; 
    return 0; 
} 

Example live here

現在爲什麼使用圍繞指針的包裝像std::reference_wrapper當人們可以爭辯人們也可以直接使用指針。國際海事組織的一個指針,有能力nullptr,改變了代碼的語義:當你有一個原始指針,它可能無效。當然,你可以假設它不是,或者把它放在評論中的某個地方,但最終你會依賴代碼無法保證的東西(這種行爲通常會導致錯誤)。

如果您載體能「引用」的對象或元素是無效的,那麼還是生的指針不是首選(對我來說):當您使用您的向量元素是有效的,那麼它引用的對象實際上是從代碼上的多個位置引用的;它是共享的。對象的「主要」引用應該是std::shared_ptr和矢量std::weak_ptr s的元素。然後,您可以(線程安全)取得有效的「參考」(共享的指針),當你需要,並把它完成時:

auto object = make_shared<int>(42); 
vector<weak_ptr<int>> v; 
v.push_back (object); 

// ... somewhere later, potentially on a different thread 
if (auto ref = v[0].lock()) { 
    // noone "steals" the object now while it's used here 
} 
// let them do what they want with the object, we're done with it ... 

最後,請把我的答案用一粒鹽,其中大部分是是基於我的意見(和經驗),可能不算作「標準做法」。

+0

'std :: vector'因爲C++ 11不需要CopyAssignable。我認爲你不能有一個引用向量的根本原因是你不能有一個指向引用的指針。因此,引用的新位置是不可能的,迭代器需要奇怪的解決方法。 – dyp