2012-09-17 30 views
7

我正在採取一個數據結構類,並且在教授的所有示例中,他總是讓他的地圖具有指向結構或容器的指針值反對拿着結構或容器本身。地圖的指針與結構/容器的地圖(C++)

他只是把它當作一種習慣嗎,還是有一個很好的理由,比如提速?

  • 我知道你可以使用數據指針來避免數據的冗餘副本,但仍然同時容納多個容器/結構中的數據。
  • 在這些例子中,這是注意的情況。數據僅在該地圖中顯示。
+2

爲什麼不問問教授?這不是一個平庸的問題。 – John3136

+0

我可以告訴你,在實踐中,對我而言,超過15年的專業C++開發和> 100萬行代碼寫在工作中,我很少將一個結構或類放入容器中。超過99%的時間我使用某種指針(最近它很可能是一個智能指針)。 – drescherjm

+0

雖然我已經回答,但我不知道這個問題是否應該被認爲是http://stackoverflow.com/questions/141337/c-stl-should-i-store-entire-objects-or-pointers-to -objects。 – jogojapan

回答

9

在我看來,有參與決定是否使用指針與對象的一些因素:

1.你還是不要你需要多態?

如果要維護一個基類對象的容器,但隨後將各種派生類的對象存儲在其中,則必須使用指針,否則將無法正確解析虛函數調用。

2.您存儲對象的大小及其對複製操作

一個爲什麼指針可能preferrable對象的關鍵原因是適宜的容器進行的各種操作涉及的複印存儲在其中的對象。對於許多存儲操作(例如,std::vector<>::push_back()std::map<>::insert()),一些檢索操作(例如,std::vector<>::operator[],然後將該對象存儲在局部變量中)以及由容器「內部」執行的一些操作(例如,當矢量超出容量時重新分配矢量,或重新調整std::unordered_map<>。請注意,根據您選擇容器的方式以及如何使用容器,複製操作可能不太重要(例如,使用std::vector<>::reserve()分配足夠的空間,使用std::vector<>::emplace_back()進行存儲,並且從不製作檢索到的元素的本地副本可能意味着沒有製作副本。但是,如果您希望創建大量副本(或者如果分析現有代碼顯示有多個副本被創建),那麼使用指針而不是對象顯然可以提供幫助,因爲指針在內存中很小並且很好地對齊。然後再次,如果你存儲的對象實際上比指針小,這沒什麼意義。

您在容器上進行

3.其他操作,其內容

即使你正在處理的對象比指針大,你希望複製操作的顯著量,使用指針不一定preferrable 。考慮一種情況,即存儲大量中等大小的對象(例如,每個對象爲16個字節),並且您經常需要遍歷整個容器並執行某種統計計算。將這些對象直接存儲在向量中時,在迭代過程中可以獲得很好的緩存效率:當您檢索一個對象時,將從內存中檢索整個緩存行,從而使得接下來幾個對象的檢索速度更快。當指針被使用時通常不是這種情況;相反,在檢索元素之後,指針必須被解除引用,導致可能未被高速緩存的內存區域的另一個移動操作。

很明顯,這一切取決於您存儲的對象的類型和大小,以及您執行的操作的類型和頻率。如果你正在處理的對象是GUI應用程序的各種類型的窗口,按鈕和菜單,你很可能想要使用指針並利用多態性。另一方面,如果您正在處理大型結構的緊湊元素,所有大小和形狀完全相同,並且您執行的操作都需要頻繁迭代或批量複製,則直接存儲對象是可以放棄的。也有可能會出現這樣的情況:如果不嘗試兩者並根據內存和時間基準的結果做出決定,則很難做出決定。


最後要注意,如果你最終使用指針,考慮正在構建的容器是否是對象的最終所有者是你在堆中分配,或者只是保持臨時指針。如果容器是這些對象的所有者,則最好使用智能指針而不是原始指針。

1

一種可能性是內容類型不可複製。

1

將對象實例直接存儲在容器中的好處是,您可以避免在指針本身使用的空間上保存的間接級別&。您可以通過直接存儲對象實例而不是存儲指針來在可以贏得兩個時間的空間效率&。如果您對處理器緩存內存的工作原理有所瞭解,不難看出如何將對象實例「內聯」存儲在容器中可以獲得真正的性能優勢。

未做關於包含的類型或容器使用模式的任何假設,則默認容器應該是std::vector<T>(而不是std::vector<T*>)。從默認選項開始,如果可以看到使用模式將如何從其他類型的結構的性能配置文件中受益,那麼您將使用除向量之外的其他值。同樣,如果指針間接是需要或者在性能方面似乎值得,則您將擁有容器存儲指向對象的指針。如果包含的類型不是可複製構建的,則需要Indirection,如果容器沒有「擁有」其對象,也需要Indirect。