我正在学习数据结构课,在教授的所有例子中,他总是使他的地图具有指向结构或容器的指针的值,而不是保持结构或容器本身。
他只是习惯这样做,还是有充分的理由来加速?
答案 0 :(得分:9)
在我看来,决定是否使用指针与对象有很多因素:
<强> 1。您或您是否需要多态性?
如果要维护基类对象的容器,然后在其中存储各种派生类的对象,则必须使用指针,否则将无法正确解析虚函数调用。
<强> 2。您存储的对象的大小及其对复制操作的适用性
指针可能更适合对象的一个关键原因是对容器执行的各种操作涉及制作存储在其中的对象的副本。这是许多存储操作(例如std::vector<>::push_back()
或std::map<>::insert()
),一些检索操作(例如std::vector<>::operator[]
,然后将对象存储在局部变量中)和一些操作的情况由容器“内部”执行,例如当矢量超出其容量或重新传播std::unordered_map<>
时重新分配矢量。请注意,复制操作可能不太重要,具体取决于您选择容器的方式以及如何使用它(例如,使用std::vector<>::reserve()
分配足够的空间,使用std::vector<>::emplace_back()
进行存储,并且从不制作本地副本检索到的元素可能意味着没有复制品。)
但是,如果您希望制作大量副本(或者如果分析现有代码显示制作了许多副本),那么使用指针代替对象显然有助于指针在内存中很小并且对齐良好。如果您存储的对象实际上小于指针,那么这将没有多大意义。
第3。您对容器及其内容执行的其他操作
即使你正在处理的对象比指针大,并且你期望大量的复制操作,使用指针也不一定是可取的。考虑一种情况,即存储大量中等大小的对象(例如,每个16个字节),并且经常需要遍历整个容器并执行某种统计计算。当您将这些对象直接存储在向量中时,您将在迭代期间获得极高的缓存效率:当您检索一个对象时,将从内存中检索整个缓存行,从而使得对下一个对象的检索更快。当使用指针时通常不是这种情况;相反,在检索元素之后,必须取消引用指针,从而导致可能未缓存的内存区域的另一个移动操作。
很明显,这一切都取决于您存储的对象的类型和大小,以及您执行的操作的类型和频率。如果您正在处理的对象是GUI应用程序的各种类型的窗口,按钮和菜单,您很可能希望使用指针并利用多态性。另一方面,如果您处理的是紧凑元素的大型结构,大小和形状都相同,并且您执行的操作涉及频繁迭代或批量复制,则直接存储对象是可以实现的。在某些情况下,如果不同时尝试并根据内存和时间基准测试结果做出决定,很难做出决定。
最后要注意的是,如果您最终使用指针,请考虑您正在构建的容器是否是在堆上分配的对象的最终所有者,或者只是维护临时指针。如果容器是这些对象的所有者,那么建议您使用智能指针而不是原始指针。
答案 1 :(得分:1)
一种可能性是内容类型不可复制。
答案 2 :(得分:1)
将对象实例直接存储在容器中的好处是可以避免一定程度的间接&amp;节省指针本身使用的空间。你可以在时间和方面赢得胜利通过直接存储对象实例而不是存储指针来提高空间效率。如果您对处理器高速缓存存储器的工作原理有所了解,那么不难看出容器中“内联”存储对象实例如何具有真正的性能优势。
不对包含的类型或容器使用模式做任何假设,默认容器应为std::vector<T>
(而不是std::vector<T*>
)。从该默认选项开始,如果您可以看到使用模式将如何从其他类型的结构的性能配置文件中受益,您将使用除向量之外的其他内容。同样,如果指针间接是需要,或者在性能方面似乎值得,那么你将拥有容器存储指向对象的指针。如果包含的类型不是可复制构造的,则需要间接,如果容器不“拥有”其对象,则也需要间接。