2014-05-19 30 views
2

我遇到了這段現有代碼,並且仍然是C++新手,我不明白爲什麼將局部變量存儲到向量中它仍然可以訪問。C++將局部變量存儲到向量中防止它在超出範圍時被破壞

下面的代碼的簡化流程,其中BackendCall是一些類時定義:

void SaveBackendCall(BackendCall* backend_call, 
        vector<BackendCall>* logged_calls) { 
    logged_calls->push_back(*backend_call); 
} 

void AddNewCall(vector<BackendCall>* logged_calls) { 
    BackendCall backend_call; // The local variable in question. 
    SaveBackendCall(&backend_call, logged_calls); 
} 

vector<BackendCall> logged_calls; 

AddNewCall(&logged_calls); 

for (auto i = logged_calls->begin(); i != logged_calls->end(); ++i) { 
    i->access_stuff(); // This still works? 
} 

會不會在AddNewCall局部變量backend_call()是函數返回後銷燬?然後我不明白什麼是實際存儲在logged_calls。

將BackendCall對象的向量轉換爲unique_ptrs向量是否有意義?

+5

一個'std :: vector'存儲它自己的一切副本。 – juanchopanza

+2

你有嚴重的誤解!可能相關:http://stackoverflow.com/questions/23620533/thread-safe-vector/23620696#23620696 –

+0

你需要使用'std :: move'來''push_back'''vector'中的'unique_ptr',for @juanchopanza已經提到了同樣的理由。 – 101010

回答

2

該向量是BackendCall對象的向量。向矢量添加對象時,會調用複製構造函數。

如果你看看SaveBackendCall(),你會注意到它是取消引用指針,這意味着它傳入的是對象的引用,而不是指針。 (如果向量存儲的指針,這將是因爲它是指向即將離開時,堆棧超出範圍危險代碼。)

那麼,什麼是這裏發生的事情是:

  1. AddNewCall()創建一個局部變量。
  2. 它將一個指向該變量的指針傳遞給SaveBackendCall()。
  3. SaveBackendCall()將對象的引用傳遞給push_back()。
  4. push_back()隱式地創建BackendCall的副本並將其添加到向量中。

根據BackendCall對象的複雜性和大小,該副本可能是一個昂貴的操作。當push_back需要調整矢量大小時,這可能會變得特別有問題。

是的,IMO使用智能指針向量來避免不必要的副本可能是有益的。

+0

實際上,解除引用不會產生引用(儘管名稱),除非您重載了一元'*'來完成此操作。 –

+0

哦,如果你的類型是移動感知的,現在便宜的矢量調整大小。 –

+0

感謝您的明確的一步一步的解釋。我想我的誤解是,我沒有意識到push_back()做了一個隱含的對象副本。 – Addison

2

正如評論者所指出的,vector<T>::push_back(someT)someT推到載體上。確實,當你進入迭代循環時,名爲backend_call的原始變量已經離開了天空中的巨大堆棧(它永遠不會溢出);或者可能它已經轉生爲i(誰知道?我不想在這裏辯論宗教)。但它的記憶以logged_calls緩衝區內的傳真形式存在。