在向量中存储对象:更好地存储对象或指向它的指针?

时间:2014-04-23 13:25:40

标签: c++ stl

我有我在整个应用程序生命周期中使用的对象:它们永远不会被破坏。我将它们存储在vector中:

declaration:
    std::vector<DoubleValue> bidDealIndexes;

construction:
    bidDealIndexes(Instrument::InstrumentsCount())

 usage:
    DoubleValue& v = bidDealIndexes[0];

或者我可以存储指针:

declaration:
    std::vector<DoubleValue*> bidDealIndexes;

construction:
    for (int i = 0; i < Instrument::InstrumentsCount(); i++) {
        bidDealIndexes.push_back(new DoubleValue());
    }

 usage:
    DoubleValue* v = bidDealIndexes[0];

问题是哪个更好?应该避免这些选项中的一个(或两个)吗?

5 个答案:

答案 0 :(得分:2)

始终首选对象,除非您需要,否则应避免使用指针。一个主要的论点是,不应该没有理由使事情复杂化,指针引入复杂性。在您的示例中,不需要指针。

答案 1 :(得分:1)

在实践中,如果您的对象是POD并且您的向量长度少于几千个项目,那么使用

可以获得更好的性能
std::vector<DoubleValue>

。与缓存未命中相比,副本非常便宜。

如果DoubleValue(非常)大或不可复制并且向量也是对象生命周期的控制器,那么使用

std::vector<std::unique_ptr<DoubleValue>>

如果DoubleValue很大而你更喜欢按值式(你应该),那么你可以考虑使用pimpl习惯用法实现DoubleValue并使其可复制或可移动,这将允许你将它存储在std :: vector中。

答案 2 :(得分:0)

如果您的矢量是恒定长度,请考虑使用std::array代替 否则,坚持std::vector元素。如果必须插入整批元素,可能需要在存储元素之前调用reserve()以避免多余的复制。

仅限专家: 如果移动对象的成本很高,并且管理添加的成员的生命周期是某些问题(例如他们保持活着直到程序结束),然后您可以考虑将指针存储为优化。不过,经过仔细的测量和考虑后才考虑这一点。

答案 3 :(得分:0)

在c ++ 11中,按照你所做的那样存储肯定是首选。在c ++ 03中,我可能仍然希望按值存储,除非性能测量显示它是一个问题。

在c ++ 11中,您使用的vector<T>(N)构造函数已更改为使用值初始化而不是复制N

按值存储更简单,在您的情况下可能会表现更好。如果表现是一个值得考虑的问题,那就看看吧。

修改:我做了一些原始测量,比较by-valueraw-pointers&amp; unique_ptr和按值排名靠前。

答案 4 :(得分:-1)

按值存储

将对象直接存储到向量(或其他STL容器)中最好留给原始类型(如果可能)。这是因为每次插入实际上都会创建正在存储的对象的副本。如果要存储类对象(例如DoubleValue类型),则每次push_back时都会调用复制构造函数。如果复制构造函数很便宜(即类中存储的内容很少而复制构造函数很少或根本没有工作),那么按值存储将使您的生活变得简单。对于更复杂的对象,甚至可能无法按值存储。例如,iostream s无法复制,因此无法将它们放入向量中。对于具有昂贵的复制构造函数的类,按值存储将减慢执行速度并增加内存占用。

摘要:用于轻量级对象

原始指针存储

随着C ++ 11(以及其他一些第三方库如boost)的出现,由于跟踪所有权和对象生命周期的复杂性,不鼓励通过原始指针进行存储。这是Stack Overflow中涵盖的完整其他主题领域。如果你不能使用C ++ 11,那么在通过原始指针存储时要小心。这可以比按值存储更高效,并允许存储无法复制的对象类型(例如iostream)。

摘要:当智能指针不可用时,用于重量级对象

通过智能指针

进行存储

C ++ 11以std::shared_ptr及其同类的形式引入了智能指针。它们通过引用计数管理对象的生命周期,并遵循RAII(资源获取是初始化)模式。净效应是从你的角度来看,它们像原始指针一样工作,但你不必担心:

  1. 指向已删除对象的指针
  2. 谁负责删除对象
  3. 我不知道shared_ptr在您的情况下是否最合适,但智能指针的使用类似于:

    std::vector<std::shared_ptr<DoubleValue> > bigDealIndexes;
    bigDealIndexes.push_back(std::shared_ptr<DoubleValue>(new DoubleValue));
    
    std::cout << "Value of first big deal: " << *(bigDealIndexes[0]) << std::endl;
    std::cout << "Member 'a':              " << bigDealIndexes[0]->a << std::endl;
    

    摘要:使用C ++ 11,boost或类似库时用于重量级对象