初始化3D矢量的最有效方法是什么?

时间:2013-08-05 15:54:21

标签: c++ performance vector

我在C ++中有一个3D字符串向量:

vector<vector<vector<string>>> some_vector

我正在尝试找到一种快速的方法为它分配内存。

我尝试用两种不同的方法来定义它:

#include<vector>
#include<iostream>
#include<ctime>
using namespace std;

#define DIM1 100
#define DIM2 9
#define DIM3 120

int main()
{
    clock_t t1_start = clock();
    vector<vector<vector<string>>> vec1(DIM1, vector<vector<string>>(DIM2, vector<string>(DIM3)));
    clock_t t1_end = clock();
    double diff1 = (t1_end - t1_start) / double(CLOCKS_PER_SEC);

    clock_t t2_start = clock();
    vector<vector<vector<string>>> vec2;
    vec2.resize(DIM1);
    for(int i = 0; i < DIM1; i++)
    {
        vec2[i].resize(DIM2);
        for(int j = 0; j < DIM2; j++)
            vec2[i][j].resize(DIM3);
    }
    clock_t t2_end = clock();

    double diff2 = (t2_end - t2_start) / double(CLOCKS_PER_SEC);

    cout<<"1st definition used time: "<<diff1<<"s"<<endl;
    cout<<"2nd definition used time: "<<diff2<<"s"<<endl;
}

我希望第一种方法(vec1)可能比第二种方法(vec2)更快。

但事实证明,第一种方法比第二种方法慢得多。在我的机器上,第一种方法使用0.245秒,而第二种方法使用0.152秒。

此外,当我将数据类型切换为int时,第一个采用0.058秒,第二个采用0.004。

我可以知道造成这种差异的原因是什么?是否有更好的方法为3D矢量分配内存?

非常感谢提前。

5 个答案:

答案 0 :(得分:13)

  

我可以知道造成这种差异的原因是什么吗?

第一个版本通过复制1-d向量构建2-d向量,然后通过复制它来构造3-d向量。这可能比没有复制时调整矢量大小要慢。但是,如果您正在构建优化,我希望差异可以忽略不计。

  

是否有更好的方法为3D矢量分配内存?

使用单个连续数组可能会更好,它包含在提供多维访问器的类中。这将使分配更加简单,并且在访问元素时也会避免某些指针解除引用(以一些算术为代价)。像这样:

template <typename T>
class vector3d {
public:
    vector3d(size_t d1=0, size_t d2=0, size_t d3=0, T const & t=T()) :
        d1(d1), d2(d2), d3(d3), data(d1*d2*d3, t)
    {}

    T & operator()(size_t i, size_t j, size_t k) {
        return data[i*d2*d3 + j*d3 + k];
    }

    T const & operator()(size_t i, size_t j, size_t k) const {
        return data[i*d2*d3 + j*d3 + k];
    }

private:
    size_t d1,d2,d3;
    std::vector<T> data;
};

答案 1 :(得分:4)

我认为我会通过分配一大块内存而不是很多小内存来优化它。这个只是2D而不是3D,但给出了基本的想法:

template <class T>
class matrix { 
    size_t columns_;
    std::vector<T> data;
public:
    matrix(size_t columns, size_t rows) : columns_(columns), data(columns*rows) {}

    T &operator()(size_t column, size_t row) { return data[row*columns_+column]; }
};

对于3D,你需要处理“飞机”(或其他东西)以及行和列,但基本思路几乎相同。

答案 2 :(得分:1)

我在Mike Seymour的代码中添加了一些功能,例如动态调整3d向量的大小以及对数据向量进行访问/分配边界检查。

template <typename T>
class vector3d 
{
public:
    vector3d(size_t d1=0, size_t d2=0, size_t d3=0, T const & t=T()) :
        d1(d1), d2(d2), d3(d3), data(d1*d2*d3, t)
    {}

    T & operator()(size_t i, size_t j, size_t k) 
    {
            return (i<=d1 && j<=d2 && k<=d3) ? data[i*d2*d3 + j*d3 + k] 
                                             : data.at(i*d2*d3 + j*d3 + k);
    }

    T const & operator()(size_t i, size_t j, size_t k) const 
    {
        return data[i*d2*d3 + j*d3 + k];
    }

    void resize(const size_t _d1=0, const size_t _d2=0, const size_t _d3=0)
    {
        data.resize(_d1*_d2*_d3);
        d1=_d1;
        d2=_d2;
        d3=_d3;
    }

    void shrink_to_fit()
    {
        data.shrink_to_fit();
    }

    const size_t length() const
    {
        return data.size();
    }

    const size_t capacity() const
    {
        return data.capacity();
    }

    const size_t x() const
    {
        return d1;
    }

    const size_t y() const
    {
        return d2;
    }

    const size_t z() const
    {
        return d3;
    }


private:
    size_t d1,d2,d3;
    std::vector<T> data;
};

用法:

vector3d<int> vec3d(2,2,2,31); //create 2x2x2 3d vector and fill it with 31
vec3d(1,1,2)=45;               //assign 45 at vec3d(1,1,2)
vec3d.resize(2,2,1);           //resize the vec3d to 2x2x1
vec3d(1,2,2)=67;               //error (its out of bounds)

答案 3 :(得分:0)

在第一种方法中初始化矢量矢量时,会分配一个临时矢量,然后将所需次数复制到外部矢量中。这意味着您有一个不必要的额外分配,并且通过从另一个使用更多内存访问的数据结构复制它们的值来初始化新元素。

按照第二种方法调整向量的大小更加难看,但避免了额外的分配。此外,新元素由默认构造函数创建,不需要从其他向量复制。这也会更快。

如果速度很重要(也许它没有,过早优化和所有这些),那么你必须使用第二种方法(或其他答案所建议的单块分配)。我不相信编译器可以简单地“优化”#34;消除第一种方法的低效率。

答案 4 :(得分:0)

要初始化3D字符串向量,您应该为每个维度逐个初始化每个维度的向量结构,例如:

  vector<vector<vector<string> > > myvector; //declare the 3D vector
  for(k=0; k<3; k++)
  {
    myvector.push_back(vector<vector<string> >()); //initialize the first index with a 2D vector
    for(i=0; i<4; i++)
    {
      myvector[k].push_back(vector<string>()); //initialize the 2 index with a row of strings
      for(j=0; j<4; j++)
      {
         result = " whatever you want to insert in the vector element";
         myvector[k][i].push_back(result); //fulfill the last index regularly
      } 
    }
  }