向量矢量的快速分配

时间:2017-01-19 16:39:45

标签: c++ vector allocation

我将3D数据存储在基于std :: vector的结构中:

std::shared_ptr< std::vector< std::vector< std::vector< Type > > > > data;

我通过在迭代向量时调用resize来分配这个结构:

    arraydata.reset(new std::vector< std::vector< std::vector< Type > > >());
    arraydata->resize(m_width);
    for (unsigned int col_index = 0; col_index < m_width; ++col_index)
    {
        (*arraydata)[col_index].resize(m_height);
        for (unsigned int line_index = 0; line_index < m_height; ++line_index)
        {
            (*arraydata)[col_index][line_index].resize(m_nbbands);
        }
    }

但是当尺寸很大时,这种分配需要花费很多时间......

有没有办法在单个操作中分配所有需要的空间(例如malloc(m_width*m_height*m_nbbands*sizeof(Type))),然后在全局空间中为每个向量分配自己的数据空间?它会更高效吗?

编辑:我测试了@ justin-time的想法

    arraydata.reset(new std::vector< std::vector< std::vector< T > > >(m_width,
         std::vector< std::vector< T > >(m_height, std::vector< T > (m_nbbands))));

给出的执行时间与原始代码相当, 4.9 s用于分配,40 s用于解除分配???

这可以在内存管理器中看到: enter image description here

我没有成功测试malloc中的分配,此代码在std::vector< T > tmp(datptr, (T*)(datptr+arraySize));失败

    unsigned int arraySize = m_nbbands*sizeof(T);
    T *datptr = (T*)malloc(m_width*m_height*arraySize);

    arraydata.reset(new std::vector< std::vector< std::vector< T > > >(m_width));
    for (unsigned int col_index = 0; col_index < m_width; ++col_index)
    {
        (*arraydata)[col_index].resize(m_height);
        for (unsigned int line_index = 0; line_index < m_height; ++line_index)
        {
            std::vector< T > tmp(datptr, (T*)(datptr+arraySize));
            (*arraydata)[col_index][line_index].swap(tmp);

            // also tested with same results:
            //(*arraydata)[col_index][line_index] = 
            //    std::vector< T >(datptr, (T*)(datptr+arraySize));

            datptr += arraySize;
        }
    }

2 个答案:

答案 0 :(得分:1)

不要使用向量向量的向量。使用具有内部数组的类,然后提供访问元素的方法。例如:

template <typename T>
class vec3d {
    std::vector<T> data;
    size_t xmax, ymax, zmax;
public:
    T& operator()(size_t x, size_t y, size_t z) 
                     { return data[x+y*xmax+z*xmax*ymax]; }
    const T& operator()(size_t x, size_t y, size_t z) 
                     { return data[x+y*xmax+z*xmax*ymax]; }
    vec3d(size_t x, size_t y, size_t z) 
                     : xmax(x), ymax(y), zmax(z), data(x*y*z) {}
    T& v(size_t x, size_t y, size_t z) { return (*this)(x,y,z); }
 };
然后

访问就像

 shared_ptr<vec3d<int>> p = make_shared<vec3d<int>>(10, 20, 30);
 p->v(5,6,7) = 14;

或      vec3d vec(5,6,7);      vec(1,2,4)= 16.0f; // Fortran样式索引。

您可能需要更多成员来允许迭代,维度等。因为这是一个单独的分配,它将更多更快。

答案 1 :(得分:0)

按照Martin Bonner的回答,我得出了以下解决方案,分配和解除分配的时间不到一秒。

可以使用arraydata[x][y][z]访问数据。

arraydata = std::make_shared< CImageStorage< T > >(m_width, 
    m_height, m_nbbands, bppixel);

template<class T>
class CImageStorage1D
{
    T* data;
    unsigned int m_nbbands;

public:
    CImageStorage1D(T* p, unsigned int nbbands) :
        data(p), m_nbbands(nbbands) {}

    T& DataPtr(unsigned int band) { return data[band]; }
    const T& DataPtr(unsigned int band) const { return data[band]; }
    T& operator[](unsigned int band) { return (data[band]); }
    const T& operator[] (unsigned int band) const { return (data[band]); }

    unsigned int size()const { return m_nbbands; }
};

template<class T>
class CImageStorage2D
{
    T* data;
    unsigned int m_height, m_nbbands, m_bppixel;

public:
    CImageStorage2D(T* p, unsigned int height, unsigned int nbbands,  
      unsigned int bppixel, std::shared_ptr< std::vector<int> > heightShift) :
        data(p), m_height(height), m_nbbands(nbbands), m_bppixel(bppixel) {}

    T* DataPtr(unsigned int height) { return (T*)(data+m_height*m_nbbands); }
    const T* DataPtr(unsigned int height) const { 
        return (T*)(data+m_height*m_nbbands); }
    CImageStorage1D<T> operator[](unsigned int height) { 
        return CImageStorage1D<T>((T*)(data+m_height*m_nbbands), m_nbbands); }
    const CImageStorage1D<T> operator[] (unsigned int height) const { 
        return CImageStorage1D<T>((T*)(data+m_height*m_nbbands), m_nbbands); }

    unsigned int size()const { return m_height; }
};

template<class T>
class CImageStorage
{
    T* data;
    unsigned int m_width, m_height, m_nbbands, m_bppixel;

public:
    CImageStorage(unsigned int width, unsigned int height, unsigned int nbbands, 
      unsigned int bppixel) :
        m_width(width), m_height(height), m_nbbands(nbbands), m_bppixel(bppixel)
    {
        data = (T*)malloc(m_width*m_height*m_nbbands*m_bppixel);
    }
    ~CImageStorage() { free(data); } 

    bool IsValid() { return (data != nullptr); }

    T** DataPtr(unsigned int width) { 
        return (T**)(data+width*m_height*m_nbbands); }
    const T** DataPtr(unsigned int width) const { 
        return (T**)(data+width*m_height*m_nbbands); }
    CImageStorage2D<T> operator[](unsigned int width) { 
        return CImageStorage2D<T>( (T*)(data+width*m_height*m_nbbands), 
            m_height, m_nbbands, m_bppixel); }
    const CImageStorage2D<T> operator[] (unsigned int width) const { 
        return CImageStorage2D<T>((T*)(data+width*m_height*m_nbbands), 
            m_height, m_nbbands, m_bppixel); }

    unsigned int size()const { return m_width; }
};