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

在C++中使用最小内存和连续形式的3D数组动态分配内存?,c++,C++,我想建立一个3D nx*ny*nz矩阵,nx,ny,nz大约是200,所以我必须使用动态分配,因为我有很多这样的矩阵,我需要以一种尽可能使用最小内存的方式来建立这些矩阵,我如何做到这一点,以及我如何以连续的形式来构建 如果维度在编译时已知,您可以使用new分配对象,尽管我可能会将其放入一个结构中,因为我一直在数组和指针之间混合类型,我几乎从不直接使用它们: struct array3d { double array[200][200][200]; }; std::auto_ptr<

我想建立一个3D nx*ny*nz矩阵,nx,ny,nz大约是200,所以我必须使用动态分配,因为我有很多这样的矩阵,我需要以一种尽可能使用最小内存的方式来建立这些矩阵,我如何做到这一点,以及我如何以连续的形式来构建

如果维度在编译时已知,您可以使用new分配对象,尽管我可能会将其放入一个结构中,因为我一直在数组和指针之间混合类型,我几乎从不直接使用它们:

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

std::auto_ptr<areay3d> array(new array3d);
显然,数组维度可以成为模板参数


如果维度仅在运行时确定,则需要分配一个连续的double数组,并自己进行数组下标计算。如果类访问元素,这也可能成为一个集合:3d数组的下标操作符将返回对2d数组的引用,等等。std::valarray是用来帮助实现这一点的,还有一些用于这一点的boost类。

如果维度在编译时已知,您可以使用new来分配对象,尽管我可能会将其放入结构中,因为我一直将数组和指针之间的类型混合在一起,我几乎从不直接使用它们:

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

std::auto_ptr<areay3d> array(new array3d);
显然,数组维度可以成为模板参数


如果维度仅在运行时确定,则需要分配一个连续的double数组,并自己进行数组下标计算。如果类访问IBG元素,这可能也会成为一个集合:3d数组的下标操作符将返回对2d数组的引用,等等。std::valarray旨在帮助实现这一点,并且也有用于此的boost类。

您可以围绕std::vector和重载操作符编写一个包装器来访问矩阵元素。元素连续存储在1D std::vector中,运算符将3D索引转换为1D索引并转换为std::vector。如果矩阵为2D,则从2D到1D的映射如下所示:

| 1 2 3 |
| 4 5 6 |  ---> [1 2 3 4 5 6 7 8 9] 
| 7 8 9 |
#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
}
这种排序称为

下面是一个类的示例,该类重载运算符以将三维索引转换为行主一维索引:

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

该库的功能与此基本相同,甚至更多,但可用于任何维度N。

您可以围绕std::vector和重载运算符编写包装器来访问矩阵元素。元素连续存储在1D std::vector中,运算符将3D索引转换为1D索引并转换为std::vector。如果矩阵为2D,则从2D到1D的映射如下所示:

| 1 2 3 |
| 4 5 6 |  ---> [1 2 3 4 5 6 7 8 9] 
| 7 8 9 |
#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
}
这种排序称为

下面是一个类的示例,该类重载运算符以将三维索引转换为行主一维索引:

#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";
}
该库的功能与此基本相同,甚至更多,但可以用于任何维度N。

使用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;
因此,整个程序可能看起来像:

| 1 2 3 |
| 4 5 6 |  ---> [1 2 3 4 5 6 7 8 9] 
| 7 8 9 |
#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
}
*广泛支持是指至少最新版本的GCC和MSVC。

使用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;
因此,整个程序可能看起来像:

| 1 2 3 |
| 4 5 6 |  ---> [1 2 3 4 5 6 7 8 9] 
| 7 8 9 |
#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
}

*广泛支持的手段,至少最新版本的GCC,和MSVC。

您可以考虑。如果内存是连续的,空间是平凡的200×200×200 * siZeof,其中T是值类型。减少的唯一方法是使用像short甚至char这样的small T,如果它们能够适合您必须表示的值的话。其他技术是避免在稀疏矩阵中存储重复值,如零,但这些值不是连续的。你的需求是矛盾的,你可以考虑。如果内存是连续的,空间是200×200×200×siZeft,其中T是值类型。减少的唯一方法是使用像short甚至char这样的small T,如果它们能够适合您必须表示的值的话。其他技术是避免在稀疏矩阵中存储重复值,如零,但这些值不是连续的。您的要求与此相矛盾,请参见关于如何使用std::valarray表示连续二维矩阵的问题:@RobertMason:确实如此。但是,它与所有的C++实现不同,它与STD::UnQuyQPTR不同,它仅在支持R值引用的系统上可用。为了自动删除一个对象,这两种方法同样有效。因此,使用std::auto_ptr似乎比std::unique_ptr更合适。请参阅关于如何使用std::valarray表示连续二维矩阵的问题:@RobertMason:确实如此。但是,它与所有的C++实现不同,它与STD::UnQuyQPTR不同,它仅在支持R值引用的系统上可用。为了自动删除一个对象,这两种方法同样有效。因此,使用std::auto_ptr似乎比std::unique_ptr更合适。OP希望矩阵元素连续存储。元素是否与此解决方案连续存储?@EmileC
或者是的,元素是连续的。根据这一点,std::array可以在数组元素之后留下填充。所以std::array不能保证是连续的。标准并不禁止它,但没有理由添加填充。任何合适的实现都会有sizeofstd::array==sizeofT[N]@emilecormer问题是在libstdc++的某个旧实现中使用tr1::array,该实现出于某种原因增加了额外的对齐要求。这可能是一个bug,看起来至少在GCC4.3.4之前就已经修复了@emilecormer OP希望矩阵元素连续存储。元素是否会与此解决方案连续存储?@EmileCormier是的,元素是连续的。据此,std::array可以在数组元素之后保留填充。所以std::array不能保证是连续的。标准并不禁止它,但没有理由添加填充。任何合适的实现都会有sizeofstd::array==sizeofT[N]@emilecormer问题是在libstdc++的某个旧实现中使用tr1::array,该实现出于某种原因增加了额外的对齐要求。这可能是一个bug,看起来至少在GCC4.3.4之前就已经修复了@EmileCormierOops,应该是Boost.MultiArray,而不是Boost.MultiIndex。它在我的机器和Ideone.com上运行良好。我甚至尝试使用vector::at代替vector:operator[]。请注意,指数是以零为基础的。适用于我的M200200200。你确定你使用的是Oops,应该是Boost.MultiArray,而不是Boost.MultiIndex。它在我的机器和Ideone.com上运行良好。我甚至尝试使用vector::at代替vector:operator[]。请注意,指数是以零为基础的。适用于我的M200200200。你确定你在用吗