【问题标题】:Usage of objects or pointers to objects as class members and memory allocation使用对象或指向对象的指针作为类成员和内存分配
【发布时间】:2011-08-21 19:25:26
【问题描述】:

这里有人问过类似的问题:

Class members that are objects - Pointers or not? C++

所以我会保持简短。

假设我有一个包含三个 stl 向量的对象。我的想法是否正确,如果他们是班级的普通成员,他们的记忆将是整个对象的“一起”?例如我的记忆看起来像 10 个块向量 A,5 个块向量 B,然后是 15 个块向量 C。然后,一旦我将更多对象插入向量 A,这样空间就会耗尽整个结构,包括向量 B 和 C 需要搬家了吗?

那是指针的参数吗?还是向量在内部只是指向分配内存的指针?同样的问题也适用于列表等......

对于重定向的成本与复制小对象的成本是否有任何经验法则?可能是 5 指针重定向 = 1 整数副本?

谢谢

【问题讨论】:

    标签: c++ class pointers member


    【解决方案1】:

    假设我有一个包含三个 stl 向量的对象。我的想法是否正确,如果他们是班级的普通成员,他们的记忆将是整个对象的“一起”?例如我的记忆看起来像 10 个块向量 A,5 个块向量 B,然后是 15 个块向量 C。

    每个vector 在包含对象中占据固定大小,与vector 当前存储的元素数量无关。 vectorvalue_type 很可能(例如 vector<int>value_type int)不会影响包含的 vector 对象本身的大小:只有堆分配的存储量vector 需要以保持其存储容量(因此它们可能是 8 或 16 或 32 个字节,但都相同,但不是 10 个“块”(无论可能是什么)、5 个块和 15 个) .

    那么,一旦我将更多对象插入向量 A 以使空间耗尽,包括向量 B 和 C 在内的整个结构都需要移动吗?

    将元素插入A 只会导致A 中的现有元素被移动(超出容量时)。 BC 永远不会受到影响。

    那是指针的参数吗?还是向量在内部只是一个指向分配内存的指针?

    是的,这是一个论据...太好了,是的,vectors 已经使用指向实际 value_type 元素存储的连续内​​存的指针。

    同样的问题也适用于列表等......

    是的,lists 也将它们的value_type 元素存储在堆上,并且对象嵌入或从list 派生的大小不受list 上的操作的影响。

    对于重定向的成本与复制小对象的成本是否有任何经验法则?可能是 5 指针重定向 = 1 整数副本?enter code here

    C++ 运行在太多平台上,因此没有好的经验法则。即使在 x86 处理器上,指令集、核心数、缓存大小、CPU 供应商/型号/代等方面的差异也可能是压倒性的。如果间接导致内存页面错误,那么它的成本最高,这非常依赖于机器上程序执行的整体情况。如果您关心,请对运行该程序的真实计算机进行基准测试,直到您找到统计相关且稳定的结果。

    【讨论】:

    • 干杯,谢谢大家,三个非常好的答案,很难选择一个。
    【解决方案2】:

    由于std::vector 是动态调整大小的,它们不可能将其元素存储为成员或成员数组。请记住,对象的大小在编译时是已知的。

    即便如此,仍然要说的是不使用指针成员。考虑这种类型:

    struct fat {
        array<double, 30> data;
        array<long, 30> more_data;
        array<char, 30> too_much_data;
    };
    

    其中array 可以是std::arraystd::tr1::arrayboost::array;它在这里只是用作大型字体的替代品。你是对的,fat 对象会很大。将成员更改为指针(或动态数组或任何类型的道德等价物)仍然为时过早:首先按原样使用对象,然后如果它太大或有其他问题,您可以动态分配 them成员:

    fat* so_much_stuff = new fat[30]();
    // Better:
    std::vector<fat> get_rid_of_it_already(30);
    

    值语义只是让事情变得更容易;只有在复制过多或大小或其他任何东西(首先测量)而不是在之前,您才应该使用(动态)容器和智能指针(它们本身遵循值语义)。

    编辑

    std::vector 总的来说并不“坏”(无论是否是会员),请参阅 cmets 中与 Tony 的讨论。

    【讨论】:

    • 很高兴您一直在考虑这一点并且写得很好,但您的推理存在两个疏忽:1) 使用 vector&lt;&gt; 进行动态分配具有调整大小和继续运行的显着优势,而当元素较少时,编译时数组大小会浪费内存,然后完全失败。 2) vector 确实 具有值语义(C++ 允许您创建具有值语义的用户定义类型是一个关键且经过深思熟虑的语言特性),因此 vectors 会被自动正确处理默认生成的析构函数和复制构造函数。
    • @Tony 你是对的,我不是提倡使用std::array 而不是std::array。我建议不要过早地使用std::vector 而不是std::array 作为成员 仅仅因为它会使对象更精简。在std::arraystd::vector(是否是会员)之间进行选择完全是另一个讨论,您已经就该主题提供了一些论据。
    • @Luc:如果您的“精简对象”警告警告说大小为 N 的 vector 不会像大小为 N 的数组那样“精简”,那肯定是真的,但向量肯定会出现当填充的大小明显小于容量 N 时,它们自己的大小,并且在超出当前容量的情况下按需调整大小。 vectors 值语义使它们成为行为良好的成员,在一般使用中应优先选择它们而不是数组。习惯性地使用array 将是“过早”的选择,因为通常很难选择一个好的容量。我仍然不确定你是否同意? :-)
    • @Tony 不,不是这样。我们也不同意或不同意,因为您正在解决(在您的第一条评论中)我不是(在我的回答中)的事情。 array 用于说明目的,因为它出现在问题中;我的回答不能为时过早因为这是前提
    • @Luc:这个问题中从未提到过数组 - 只有向量......:-/。无论如何,不​​用担心......
    【解决方案3】:

    集合类是在内部使用指针实现的——您不必担心它们会耗尽空间。至于复制开销,除非您已通过分析您的代码证明这是一个问题,否则不要担心。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-06
      • 2023-01-19
      • 2014-01-02
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多