簡體   English   中英

我應該存儲整個對象,還是指向容器中對象的指針?

[英]Should I store entire objects, or pointers to objects in containers?

從頭開始設計新系統。 我將使用STL來存儲某些長壽命對象的列表和地圖。

問題:我是否應該確保我的對象具有復制構造函數並在我的STL容器中存儲對象的副本,或者通常更好地自行管理生命和范圍,並將指針存儲在我的STL容器中的那些對象中?

我意識到這在細節方面有點短暫,但我正在尋找“理論上”更好的答案,如果它存在,因為我知道這兩種解決方案都是可能的。

使用指針的兩個非常明顯的缺點:1)我必須在超出STL的范圍內管理這些對象的分配/釋放。 2)我無法在堆棧上創建臨時對象並將其添加到我的容器中。

還有什么我想念的嗎?

因為人們正在考慮使用指針的效率。

如果您正在考慮使用std :: vector並且如果更新很少並且您經常迭代您的集合並且它是非多態類型存儲對象“副本”將更有效,因為您將獲得更好的引用位置。

Otoh,如果更新是常見的存儲指針將節省復制/重定位成本。

這真的取決於你的情況。

如果你的對象很小,並且對象的副本是輕量級的,那么在我看來將數據存儲在stl容器中是簡單易行的,因為你不必擔心生命周期管理。

如果對象很大,並且默認構造函數沒有意義,或者對象的副本很昂貴,那么使用指針存儲可能就是要走的路。

如果您決定使用指向對象的指針,請查看Boost指針容器庫 此boost庫包裝所有STL容器以與動態分配的對象一起使用。

每個指針容器(例如ptr_vector)在將對象添加到容器時獲取對象的所有權,並為您管理這些對象的生命周期。 您還可以通過引用訪問ptr_容器中的所有元素。 這可以讓你做的事情

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

這些類包裝STL容器並使用所有STL算法,這非常方便。

還有用於將容器中指針的所有權轉移給調用者的設施(通過大多數容器中的釋放功能)。

如果您正在存儲polymporhic對象,則總是需要使用一組基類指針。

也就是說,如果您計划在集合中存儲不同的派生類型,則必須存儲指針或被切片守護程序吃掉。

對不起,在活動結束后3年內跳了一下,但這里有一個警示...

在我的上一個大項目中,我的中心數據結構是一組相當簡單的對象。 大約一年的項目,隨着需求的發展,我意識到對象實際上需要是多態的。 經過幾周的困難和討厭的腦外科手術將數據結構修復為一組基類指針,並處理對象存儲,轉換等所有附帶損害。 我花了幾個月的時間才說服自己新代碼正在運行。 順便說一下,這讓我想到了C ++的對象模型設計得很好。

在我目前的大項目中,我的中心數據結構是一組相當簡單的對象。 大約一年的項目(恰好是今天),我意識到對象實際上需要是多態的。 回到網上,找到了這個帖子,並找到了Nick的Boost指針容器庫的鏈接。 這正是我上次要寫的所有內容,所以這次我會試一試。

無論如何,道德,對我來說:如果你的規范不是100%一成不變的話,那就去尋找指針,你可能會在以后節省很多工作。

為什么不充分利用兩個世界:做一個智能指針容器(如boost::shared_ptrstd::shared_ptr )。 您不必管理內存,也不必處理大型復制操作。

通常將對象直接存儲在STL容器中是最好的,因為它最簡單,最有效,並且最容易使用該對象。

如果您的對象本身具有不可復制的語法或者是抽象基類型,則需要存儲指針(最簡單的方法是使用shared_ptr)

你似乎很好地掌握了這種差異。 如果對象很小並且易於復制,那么一定要存儲它們。

如果沒有,我會考慮將智能指針(不是auto_ptr,一個引用計數智能指針)存儲到您在堆上分配的指針。 顯然,如果你選擇智能指針,那么你就無法存儲臨時堆棧分配的對象(正如你所說)。

@ Torbjörn對切​​片提出了一個很好的觀點。

使用指針會更有效,因為容器只會復制指針而不是完整對象。

這里有一些關於STL容器和智能指針的有用信息:

為什么在標准容器中使用std :: auto_ptr <>是錯誤的?

如果要在代碼中的其他地方引用對象,則存儲在boost :: shared_ptr的向量中。 這可確保在調整向量大小時指向對象的指針仍然有效。

即:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

如果沒有其他人存儲指向對象的指針,或者列表沒有增長和縮小,只需存儲為普通舊對象:

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol

這個問題一直困擾着我。

我傾向於存儲指針,但我有一些額外的要求(SWIG lua包裝)可能不適用於你。

這篇文章中最重要的一點是使用你的對象 自己測試它

我今天這樣做是為了測試在1000萬個對象的集合上調用成員函數的速度,500次。

該函數根據xdir和ydir(所有浮點成員變量)更新x和y。

我使用std :: list來保存兩種類型的對象,我發現將對象存儲在列表中比使用指針略快。 另一方面,性能非常接近,所以它歸結為它們將如何在您的應用程序中使用。

作為參考,在我的硬件上使用-O3指針需要41秒才能完成,原始對象需要30秒才能完成。

暫無
暫無

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

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