2012-09-17 31 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。