在c ++中使用最小内存和连续形式的3d数组的动态分配内存?

时间:2012-03-18 16:27:51

标签: c++

我想构建一个nx,ny,nz约为200的3D nx * ny * nz矩阵,所以我必须使用动态分配,因为我有很多这些矩阵,我需要以这样的方式构建这些矩阵尽可能使用最小内存我该怎么做?我怎样才能建立连续的形式?

3 个答案:

答案 0 :(得分:2)

使用C ++ 11:

template<typename T,size_t M,size_t N,size_t O>
using Matrix3D = std::array<std::array<std::array<T,O>,N>,M>;

std::unique_ptr<Matrix3D<double,200,200,200>> mat(new Matrix3D<double,200,200,200>);

(*mat)[m][n][o] = 10.0;

如果编写make_unique函数,变量声明将变为:

auto mat = std::make_unique<Matrix3D<double,200,200,200>>();

所以整个程序可能看起来像:

#include <memory> // std::unique_ptr for convenient and exception safe dynamic-memory management
#include <array>  // std::array because it behaves much better than raw arrays 

template<typename T,size_t M,size_t N,size_t O>
using Matrix3D = std::array<std::array<std::array<T,O>,N>,M>;

// A simple `make_unique`
template<typename T,typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

int main() {
    auto mat = make_unique<Matrix3D<double,200,27,200>>();
    (*mat)[199][26][199] = 10.0; // store 10.0 in the last element
}

请记住,这是C ++ 11,有些编译器还没有实现我正在使用的所有功能。特别是我所知道的唯一支持模板别名(using Matrix3D =行)的已发布编译器是clang 3.0。下一版GCC将支持它。 GCC和Clang都支持变量模板(用于实现make_unique),但VS11不支持MSVC。

这是一个仅使用广泛支持的* C ++ 11功能的版本:

#include <memory>
#include <array>

template<typename T,size_t M,size_t N,size_t O>
struct Matrix3D {
    std::array<std::array<std::array<T,O>,N>,M> array;
};

// A simple `make_unique` that supports only zero-argument construction.
template<typename T>
std::unique_ptr<T> make_unique() {
    return std::unique_ptr<T>(new T);
}

int main() {
    auto mat = make_unique<Matrix3D<double,200,27,200>>();
    mat->array[199][26][199] = 10.0; // store 10.0 in the last element
}

*广泛支持至少意味着最新版本的GCC和MSVC。

答案 1 :(得分:1)

如果在编译时已知维度,你可以使用new分配对象,虽然我可能会把它放在一个结构中因为我在数组和指针之间保持混合类型(我几乎没有直接使用它们):

struct array3d {
    double array[200][200][200];
};

std::auto_ptr<areay3d> array(new array3d);

显然,数组维度可以成为模板参数。

如果仅在运行时确定维度,则需要分配double的连续数组并自行执行数组下标计算。如果类访问元素,这可能也会成为一个集合:3d数组的下标运算符将返回对2d数组的引用,等等。std::valarray<double>旨在帮助解决这个问题,并且有针对此的增强类。好。

答案 2 :(得分:1)

您可以围绕std::vector和重载operator()编写包装来访问矩阵元素。元素在1D std::vectoroperator()中连续存储,将3D索引转换为std::vector的1D索引。如果矩阵是2D,这就是从2D到1D的映射看起来像:

| 1 2 3 |
| 4 5 6 |  ---> [1 2 3 4 5 6 7 8 9] 
| 7 8 9 |

此排序称为row major

这是一个重载operator()以将3D索引转换为行主要1D索引的类的示例:

#include <iostream>
#include <vector>

template <class T>
class Matrix3D
{
public:
    Matrix3D(size_t m, size_t n, size_t o)
    : m_(m), n_(n), o_(o), data_(m*n*o) {}

    T& operator()(size_t i, size_t j, size_t k)
    {
        return data_[(i * n_ * o_) + (j * o_) + k];
    }

    const T& operator()(size_t i, size_t j, size_t k) const
    {
        return data_[(i * n_ * o_) + (j * o_) + k];
    }

private:
    std::vector<T> data_;
    size_t m_, n_, o_;
};

int main()
{
    Matrix3D<float> m(4, 3, 2);
    m(0,0,0) = 12.3f;
    m(3,2,1) = 45.6f;
    std::cout << m(0,0,0) << " " << m(3,2,1) << "\n";
}

Boost.MultiArray库与此基本相同(以及更多),但可以用于任何维度N.