如何避免使用STL重新分配(C ++)

时间:2010-02-28 15:33:37

标签: c++ memory stl dynamic-memory-allocation

这个问题来源于主题:

vector reserve c++

我正在使用vector<vector<vector<double> > >类型的数据结构。在添加项目(double s)之前,无法知道每个向量的大小(外部向量除外)。我可以得到每个“维度”中项目数量的近似大小(上限)。

使用共享指针的解决方案可能是可行的方法,但我想尝试一种解决方案,其中vector<vector<vector<double> > >只有.reserve()足够的空间(或以其他方式分配足够的空间)存储器)。

A.reserve(500)(假设500是大小,或者大小的上限)足以容纳大尺寸的“2D”矢量,比如[1000] [10000]?

我的问题的原因主要是因为在A时我无法合理估算.reserve(500)内部的大小。

我的问题的一个例子:

vector<vector<vector<int> > > A;
A.reserve(500+1);
vector<vector<int> > temp2;
vector<int> temp1 (666,666);
for(int i=0;i<500;i++)
{
  A.push_back(temp2);
  for(int j=0; j< 10000;j++)
  {
    A.back().push_back(temp1);
  }
}

这是否确保没有为A?

重新分配

如果在创建时添加了temp2.reserve(100000)temp1.reserve(1000),这将确保根本不会发生重新分配?

在上文中,请忽略由于保守的.reserve()电话而浪费内存的事实。

提前谢谢大家!

10 个答案:

答案 0 :(得分:1)

如何预先在A中预留500个条目足够[1000] [1000]?

您需要保留&gt; 1000为A(这是你的实际上限值),然后每当你向A添加一个条目时,在中保留另外1000个左右(再次,上限但第二个 value)。

A.reserve(UPPERBOUND);

for(int i = 0; i < 10000000; ++i)
   A[i].reserve(UPPERBOUND);

BTW,reserve保留元素的数量,而不是字节数。

答案 1 :(得分:1)

您的示例将导致大量复制和分配。

vector<vector<vector<double>>>  A;
 A.reserve(500+1);
 vector<vector<double>>  temp2; 
vector<double> temp1 (666,666);
 for(int i=0;i<500;i++) 
{
 A.push_back(temp2);
 for(int j=0; j< 10000;j++)
 {
 A.back().push_back(temp1);
 }
} 

问:这是否可以确保不对A进行重新分配? 答:是的。

问:如果temp2.​​reserve(100000)和temp1.reserve(1000)在创建时添加,这将确保根本不会发生任何重新分配?
答:这里temp1已经在创建时知道它自己的长度并且不会被修改,所以添加temp1.reserve(1000)只会强制进行不需要的重新分配。
我不知道矢量类在他们的副本ctor中复制了什么,使用A.back()。reserve(10000)应该适用于这个例子。
更新:刚刚使用g ++测试,不会复制temp2的容量。所以temp2.​​reserve(10000)将不起作用。

请在发布代码时使用源格式化,使其更具可读性: - )。

答案 2 :(得分:1)

reserve功能可以为您vector A正常使用,但不会像您期望的那样temp1temp2

temp1向量初始化为给定大小,因此将使用正确的capacity进行设置,只要您计划,就不需要使用reserve不要增加它的大小。

关于temp2capacity属性不会在副本中转移。考虑每当您使用push_back功能时,您都会向vector添加副本,代码如下

vector<vector<double>> temp2;
temp2.reserve(1000);
A.push_back(temp2); //A.back().capacity() == 0

您只是增加了临时释放的临时分配内存,而不是按预期增加vector元素容量。如果您真的想使用vector vector作为解决方案,则必须执行以下操作

vector<vector<double>> temp2;
A.push_back(temp2);
A.back().reserve(1000); //A.back().capacity() == 1000

答案 3 :(得分:1)

有一天我遇到了同样的问题。一个干净的方法(我认为)是编写自己的Allocator并将其用于内部向量(std::vector<>的最后一个模板参数)。我们的想法是编写一个实际上不分配内存的分配器,只是在外部向量的内存中返回正确的地址。如果您知道每个先前向量的大小,就可以轻松地知道这个地址。

答案 4 :(得分:1)

为了避免复制和重新分配数据结构,例如vector<vector<vector<double> > >,我建议如下:

vector<vector<vector<double> > > myVector(FIXED_SIZE);

为了“赋值”它,在你真正知道它们的所需维度之前不要定义你的内部向量,然后使用swap()而不是赋值:

vector<vector<double> > innerVector( KNOWN_DIMENSION );
myVector[i].swap( innerVector );

请注意push_back()将执行复制操作并可能导致重新分配,而swap()则不会(假设两个向量都使用相同的分配器类型)。

答案 5 :(得分:0)

在我看来,你需要一个真正的矩阵类而不是嵌套向量。看看boost,它有一些强大的稀疏矩阵类。

答案 6 :(得分:0)

好的,现在我自己做了一些小规模的测试。我使用从http://www.tek-tips.com/faqs.cfm?fid=5575获得的“2DArray”来表示分配内存静态的结构。对于动态分配,我几乎按照原始帖子中的说明使用了向量。

我测试了以下代码(hr_time是在网络上发现的一个时间例程,由于反垃圾邮件,我很遗憾无法发布,但是归功于David Bolton提供它)

#include <vector>
#include "hr_time.h"
#include "2dArray.h"
#include <iostream>
using namespace std;

int main()
{
    vector<int> temp;

    vector<vector<int> > temp2;

    CStopWatch mytimer;

    mytimer.startTimer();

    for(int i=0; i<1000; i++)
    {
        temp2.push_back(temp);
        for(int j=0; j< 2000; j++)
        {
            temp2.back().push_back(j);
        }
    }

    mytimer.stopTimer();

    cout << "With vectors without reserved: " << mytimer.getElapsedTime() << endl;

    vector<int> temp3;

    vector<vector<int> > temp4;

    temp3.reserve(1001);

    mytimer.startTimer();

    for(int i=0; i<1000; i++)
    {
        temp4.push_back(temp3);
        for(int j=0; j< 2000; j++)
        {
            temp4.back().push_back(j);
        }
    }

    mytimer.stopTimer();

    cout << "With vectors with reserved: " << mytimer.getElapsedTime() << endl;

    int** MyArray = Allocate2DArray<int>(1000,2000);

    mytimer.startTimer();
    for(int i=0; i<1000; i++)
    {
        for(int j=0; j< 2000; j++)
        {
            MyArray[i][j]=j;
        }
    }


    mytimer.stopTimer();

    cout << "With 2DArray: " << mytimer.getElapsedTime() << endl;

    //Test
    for(int i=0; i<1000; i++)
    {
        for(int j=0; j< 200; j++)
        {
            //cout << "My Array stores :" << MyArray[i][j] << endl;
        }
    }

    return 0;
}

事实证明,这些尺寸大约有10倍。因此,我应该重新考虑动态分配是否适合我的应用,因为速度至关重要!

答案 7 :(得分:0)

为什么不在构造函数中对内部容器和reserve()进行子类化?

答案 8 :(得分:0)

如果Matrix确实变得非常庞大且备用,我也会尝试使用稀疏矩阵库。否则,在搞乱分配器之前,我会尝试用deque替换vector。 deque不会重新分配增长,并提供几乎与矢量一样快的随机访问。

答案 9 :(得分:0)

这或多或少回答here。所以你的代码看起来像这样:

vector<vector<vector<double> > > foo(maxdim1,
    vector<vector<double> >(maxdim2,
    vector<double>(maxdim3)));