首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++中分配N维数组

在C++中分配N维数组
EN

Code Review用户
提问于 2016-08-19 15:49:16
回答 2查看 1.9K关注 0票数 3

我需要分配T类型的n维数组,目前我正在使用以下函数.有更好的方法吗?而且,理想情况下,我希望分配一个一维数组并将其作为一个not数组访问,但我想不出更好的方法来实现它。使用现有的矩阵库不是一个选项,因为我希望访问原始指针。

代码语言:javascript
复制
template <class T, class Ti>
T*** allocate_3d_array(Ti nx, Ti ny, Ti nz){
    T*** A = new T**[nx];
    for(Ti i(0); i < nx; ++i){
            A[i] = new T*[ny];
            for(Ti j(0); j < ny; ++j){
                A[i][j] = new T[nz];                    
                for(Ti k(0); k < nz; ++k){
                    A[i][j][k]= 0.;
                }
            }
    }
    return A;
}
template <class T, class Ti>
void release_3d_array(T*** A, Ti nx, Ti ny, Ti nz){
    for (Ti i = 0; i < nx; ++i){
            for (Ti j = 0; j < ny; ++j){
                delete[] A[i][j];
            }
            delete[] A[i];
    }
    delete[] A;
}

template <class T, class Ti>
T** allocate_2d_array(Ti nx, Ti ny){
    T** A = new T*[nx];
    for(Ti i(0); i < nx; ++i){
        A[i] = new T[ny];
    }
    return A;
}

template <class T, class Ti>
void release_2d_array(T** A, Ti nx, Ti ny){
    for (Ti i = 0; i < nx; ++i){
        delete[] A[i];
    }
    delete[] A;
}


template <class T, class Ti>
T* allocate_1d_array(Ti nx){
    T *A = new T[nx];
    return A;
}

template <class T, class Ti>
    void release_1d_array(T* A, Ti nx){
    delete[] A;
}
EN

回答 2

Code Review用户

发布于 2016-08-19 20:00:58

我会在洛基回答的基础上再加一些。你忽略的主要问题是类型安全。通过使这些间接方向,你基本上是从标准库模板部分可以提供给你的所有东西。最重要的是,decltype()sizeof()和许多依赖编译时类型信息的其他函数变得无用。这是至关重要的事情,被修复。

建议实现

首先,我们需要找出如何制作方便的类型/类型别名来为我们生成具有指定维度的数组类型?

单词类型表明它需要编译时间,最好的(可能是唯一的)方法是模板元编程。

其方法如下:我们采用一个类型和一个维度序列(例如,int, 3, 4, 5),并从末尾开始,将每个维度附加到该类型。

代码语言:javascript
复制
#ifndef GENERATE_DIMENSIONS_H
#define GENERATE_DIMENSIONS_H
#include <cstddef>

template <typename T, std::size_t first, std::size_t ... rest>
struct generate_dimensions
{
    using type = typename generate_dimensions<T, rest...>::type[first];
};

template <typename T, std::size_t first>
struct generate_dimensions<T, first>
{
    using type = T[first];
};

template <typename T, std::size_t first, std::size_t ... rest>
using generate_dimensions_t = typename generate_dimensions<T, first, rest...>::type;

#endif

递归在到达一维情况时停止,并在返回的过程中追加其他维度。数组的分配非常简单:

代码语言:javascript
复制
new generate_dimensions_t<int, 3, 4, 5>;

如果您想推迟构建,我们可以这样写:

代码语言:javascript
复制
operator new(sizeof(generate_dimensions_t<int, 3, 4, 5>));

数组类型的大小是正确计算,这是我们的目标之一。

差不多就是这样了。保持冷静,拥抱C++。

票数 3
EN

Code Review用户

发布于 2016-08-19 16:57:35

回答问题.

我需要分配T类型的n维数组,目前我正在使用以下函数.有更好的方法吗?

是。创建一个类来包装2/3D数组,以便以异常安全的方式正确地进行内存管理。

您可能需要与其他库进行接口的原始指针,但这并不意味着您应该积极地管理该指针。您需要将它们包装在一个类中,以便为您提供所有内存管理,但在需要时提供对原始指针的访问。

示例:

代码语言:javascript
复制
template<typename T>
class Array3D
{
    private:
    static T*** allocate_3d_array(std::size_t nx, std::size_t ny, std::size_t nz)
    {
        T*** A = new T**[nx];
        for(std::size_t i = 0; i < nx; ++i)
        {
            A[i] = new T*[ny];
            for(std::size_r j(0); j < ny; ++j)
            {
                A[i][j] = new T[nz];                    
                for(std::size_t k(0); k < nz; ++k)
                {
                    A[i][j][k]= 0.;
                }
            }
        }
        return A;
    }
    static void release_3d_array(T*** A, std::size_t nx, std::size_t ny, std::size_t nz)
    {
        for (std::size_t i = 0; i < nx; ++i)
        {
            for (std::size_t j = 0; j < ny; ++j)
            {
                delete[] A[i][j];
            }
            delete[] A[i];
        }
        delete[] A;
    }
    T*** data;
    std::size_t  xSize;
    std::size_t  ySize;
    std::size_t  zSize;
public:
    Array3D(std::size_t xSize, std::size_t ySize, std::size_t zSize)
        : data(allocate_3d_array(xSize, ySize, zSize)
        , xSize(xSize)
        , ySize(ySize)
        , zSize(zSize)
    {}
    ~Array3D()
    {
        release_3d_array(data, xSize, ySize, zSize);
    } 

    // Disable Copy for now
    Array3D(Array3D const&)            = delete;
    Array3D& operator=(Array3D const&) = delete;

    // Disable Move for now
    Array3D(Array3D&&)                 = delete;
    Array3D& operator=(Array3D&&)      = delete;


    // Allow access to the underlying data when calling C function.
    operator T***()
    {
        return data;
    }
};

现在,您可以创建一个3D数组,在这个数组中,内存在任何时候都是正确管理的(因此不会泄漏)。当您将数据传递给C函数时,它将将自身转换为T***,以便可以使用它(我假设C函数是不拥有的,因此不会破坏数组,并且对象处于同一个线程中,因此,只要函数调用,它就会存活)。

如果您想使用operator[]访问对象,请参阅下面的“我已经链接到了一篇堆栈溢出文章”。

复制可能不是你想要的三维数组。但是如果您需要它,您将需要实现上述适当的功能。

移动是一种高级的复制形式。在你理解移动语义之前不要使用。同样,您将需要实现上述功能。

而且,理想情况下,我希望分配一个一维数组并将其作为一个not数组访问,但我想不出更好的方法来实现它。

是的,这将使内存使用更加有效,因此将是实现多维arrya的首选技术。我要你参考我写的一篇文章,这样你才能正确地指出方向。

参见:如何为2D数组的包装类重载数组索引操作符?作为一个例子。

使用现有的矩阵库不是一个选项,因为我希望访问原始指针。

老实说,我对这一说法感到有点惊讶。在我看来,这是任何想要与C库接口的库的要求。没有这种能力是令人震惊的。也许你错过了。你想用什么图书馆?

与C++相比,您当前的风格肯定是缺乏的。您实现这一点的方式并没有为在C上使用C++提供任何好处。

泛型审查

我认为不需要模板类型的Ti

代码语言:javascript
复制
template <class T, class Ti>
T*** allocate_3d_array(Ti nx, Ti ny, Ti nz){

在我看来,这始终是一个整数类型。选一个。如果您这样做是出于某种特定的原因,而我还没有推断,那么应该在代码的注释中指出这一点(如果对我来说不太明显,那么我认为没有其他人理解它)。

使用零初始化。

代码语言:javascript
复制
new T;  // Alocates memory for T but does default initialization.
        // for POD types this means nothing is done and the value is
        // indeterminate.

new T();// Allocates memory for T but does zero initialization.
        // for pod types it means the values have zero.


            A[i][j] = new T[nz];                    
            for(Ti k(0); k < nz; ++k){
                A[i][j][k]= 0.;
            }

            // Can be replaced with:
            A[i][j] = new T[nz]();
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/139156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档