矢量指针内存分配的矢量

Vector of vector pointer memory allocation

本文关键字:分配 指针 内存      更新时间:2023-10-16

首先我想说,我有一个向量,里面有一千个向量。这些内部向量中的每一个内部都有数千个数字。我想保持内存管理的安全,并尽可能减少内存使用。

我想问一下,如果我有一个类似于下面的代码

    int size = 10;
vector<vector<double>>* something = new vector<vector<double>>(size);
vector<double>* insideOfSomething;
for(int i = 0; i < size; i++){
    insideOfSomething = &(something->at(i));
    //...
    //do something with insideOfSomething 
    //...
}

我知道"某物"会堆积起来。我不明白的是向量放在哪里,"在某物内部"指的是什么?如果它们是在堆栈中创建的,那么这意味着我有一个向量指针,它指向堆中的一个向量,里面有在堆栈中生成的向量?(我现在很困惑。)

如果我有一个类似于下面的代码;

    vector<vector<double>*>* something = new vector<vector<double>*>(size);
vector<double>* insideOfSomething;
for(int i = 0; i < size; i++){
    something->at(i) = new vector<double>();
    insideOfSomething = something->at(i);
    //...
    //do something with inside insideOfSomething 
    //...
}

知道吗,我所有的向量都存储在堆中,对吧?

根据内存管理,哪一个更有用?

您应该避免在堆上分配向量,而只在堆栈上声明它们,因为向量将为您管理其在堆上的对象。在任何想避免创建副本的地方,都可以使用引用或const引用(这是必要的)。

vector<vector<double> > something(size);
for(int i = 0; i < size; i++)
{
    vector<double> &insideOfSomething = something.at(i);
    //use insideOfSomething
}

让我们对vector进行一个随机、简单的实现,因为我认为这将对您有所帮助。

template <class T, class Alloc>
class vector
{
private:
    T* buffer;
    std::size_t vector_size;
    std::size_t vector_capacity
    Alloc alloc;
public:
    ...
};

在这种情况下,如果我们写:

vector<int> v;
v.push_back(123);

指针buffer、积分vector_sizevector_capacity以及分配器对象alloc都将在堆栈上创建(同时分配结构填充和对齐所需的任何额外内存)。

然而,向量本身将在堆上分配内存,这个buffer指针将把它的基地址存储到堆上。它将始终在堆中,并将包含我们所认为的向量的实际内容。

这仍然比这个更有效率:

vector<int>* v = new vector<int>;
v->push_back(123);
...
delete v;

因为这将涉及向量本身(包括其数据成员)的堆分配/释放,以及向量本身为其内部内容(缓冲区)分配的内存。它还引入了一个额外的间接级别。

现在,如果我们有一个向量Somethings(向量的向量或其他任何东西):

vector<Something> v;

这些Something实例总是在连续堆缓冲区内分配,因为它们将驻留在向量内部创建和销毁的动态分配的内存块中。

在向量中<>堆中存储的所有数据我认为你应该简单地使用

vector< vector<double> > something;

我想保持内存管理的安全,并尽可能减少内存使用。

然后

vector<vector<double>>* something = new vector<vector<double>>(size);

已经不好了。正如在其他答案中所说,vector已经在堆上有了它的数据,不需要为了实现这一点而摆弄new。事实上,物体的位置就像

       S t a c k                              H e a p
                                        (vector<double>) sthng[0]
(vector<vector<double>>) sthng          (vector<double>) sthng[1]
                                                ...
                                             - - - - - -
                                         (double) sthng[0][0]
                                         (double) sthng[0][1]
                                                ...
                                             - - - - - -
                                         (double) sthng[1][0]
                                         (double) sthng[1][1]
                                                ...

(当然,堆上的块没有特定的排序)

Joe和hired777的回答解释了无论发生什么,都会在堆上分配一个向量。我将试着对造成这种情况的原因给出一些见解。

向量是一个可调整大小的容器。通常,当它达到容量时,它的大小会翻倍,这意味着它需要能够分配比已经分配的更多的内存。因此,即使在函数内部和堆栈上声明vector,它在内部也会持有指向堆上数据的指针,当超出函数的范围时,它的析构函数会从堆中删除这些数据。