c++ 向量如何为包含内部向量的对象保留内存?

wa7juj8i  于 2023-06-25  发布在  其他
关注(0)|答案(3)|浏览(161)

假设我有一个这样的对象:

struct MyObject
{
    int someId;
    std::vector<int> innerVector;

    MyObject(int a)
    {
        innerVector.reserve(a);
    }
};

我试着用这种方式保留一个向量MyObject

std::vector<MyObject> myObjects;
myObjects.reserve(maxItemsToBeAllowed);

如果每个MyObject上的innerVector向量的大小不可预测,它如何保留内存?它是否只是“尝试”,如果innerVector更大的情况下在运行时重新分配?

brccelvz

brccelvz1#

类型的大小永远是不可预测的。它在编译时总是已知的,并且在程序的整个生命周期中永远不会改变。std::vector在vector对象的内存中不包含它的元素。vector对象包含一些指向动态分配内存的指针。

vsmadaxz

vsmadaxz2#

请记住,std::vector的内核很可能是使用动态内存分配来存储的,因此基本对象的大小是可以预测的,并且是预先知道的。
它所做的就是在调用reserve(n)时保留 N 倍的占用空间。一旦这些条目被使用,它们可能需要额外的分配,除非,例如,您只是将它们保留为空。
换句话说,sizeof(std::vector<X>)是可预测的。这种结构的总内存成本是完全不同的。
另一方面,如果你有std::array<std::array<X>>,那就完全不同了。它们的行为更像C数组。

7cjasjjr

7cjasjjr3#

std::vector::reserve只是确保可以创建一定数量的元素,而无需重新分配向量的后备存储。使用此函数不会创建新元素。(如果需要重新分配内存,我将忽略那些需要从现有元素中移动构造的元素。)
下面的代码仍然会导致后备存储器的最佳分配数量:

struct MyObject
{
    int someId;
    std::vector<int> innerVector;

    MyObject(int a)
    {
        innerVector.reserve(a);
    }
};

class VectorManager
{
    std::vector<MyObject> m_objects;
public:
    VectorManager() noexcept
    {}

    void ReserveOuter(size_t n)
    {
        m_objects.reserve(n);
    }

    void AddInner(int const count, int const value)
    {
        auto& newObject = m_objects.emplace_back(count); // add a new MyObject constructing it using count as constructor parameter
        for (int i = 0; i < count; ++i)
        {
            newObject.innerVector.push_back(value);
        }
    }
};

int main()
{
    VectorManager vm;
    size_t const max = 50;
    vm.ReserveOuter(max); // resize outer vector according to requires max
    for (size_t i = 0; i != max; ++i)
    {
        vm.AddInner(i, i);
    }
}

如果内部向量的大小对于所有MyObject s都是,则该逻辑仍然使用用于向量的备份存储的最佳分配数。上面的代码仍然只有一个外部向量的分配

vm.ReserveOuter(max);

并且每个MyObject创建一个分配

vm.AddInner(i, i);

如果不更改类,则无法改进此数量,因为每个向量需要一个分配。(为了简单起见,我忽略了从未填充任何元素的向量;如果一些向量保持为空,则分配的数量仍然是最优的。)

相关问题