What is the most efficient way to initialize a 3D vector?

40,837

Solution 1

May I know what cause such difference?

The first version constructs a 2-d vector by copying a 1-d vector, and then constructs the 3-d vector by copying that. This might be slower than resizing the vectors without copying. However, I'd hope that the difference would be negligible if you're building with optimisation.

And is there better way to allocate memory for a 3D vector?

It might be better to use a single contiguous array, wrapped in a class that provides multi-dimensional accessors. This would make allocation much simpler, and would also avoid some pointer dereferencing when accessing elements (at the cost of a bit of arithmetic). Something like this:

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;
};

Solution 2

I think I'd optimize it by allocating one large block of memory instead of a lot of little ones. This one is only 2D instead of 3D, but gives the basic idea:

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]; }
};

For 3D, you'll need to deal with "planes" (or something) along with rows and columns, but the basic idea is pretty much the same.

Solution 3

I added several features to Mike Seymour's code such as dynamically resize the 3d vector and on access/assign bounds checking for data vector.

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;
};

Usage:

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)

Solution 4

To initialize a 3D string vector you shall initialize the vector structure for each dimension one at a time and for each index, for instance:

  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
      } 
    }
  }
Share:
40,837
ChangeMyName
Author by

ChangeMyName

Updated on September 09, 2021

Comments

  • ChangeMyName
    ChangeMyName over 2 years

    I have a 3D string vector in C++:

    vector<vector<vector<string>>> some_vector
    

    That I am trying is to find a fast method to allocate memory for it.

    I tried to define it with two different methods as follow:

    #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;
    }
    

    I expect that the first method (vec1) could be faster than the 2nd one (vec2).

    But it turned out that the 1st method is much slower than the 2nd. On my machine, the 1st method used 0.245 seconds, while the 2nd method used 0.152 seconds.

    Moreover, when I switch the data type to int, the 1st one took 0.058 second, and the 2nd took 0.004.

    May I know what cause such difference? And is there better way to allocate memory for a 3D vector?

    Many thanks in advance.