我需要分配T类型的n维数组,目前我正在使用以下函数.有更好的方法吗?而且,理想情况下,我希望分配一个一维数组并将其作为一个not数组访问,但我想不出更好的方法来实现它。使用现有的矩阵库不是一个选项,因为我希望访问原始指针。
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;
}发布于 2016-08-19 20:00:58
我会在洛基回答的基础上再加一些。你忽略的主要问题是类型安全。通过使这些间接方向,你基本上是从标准库模板部分可以提供给你的所有东西。最重要的是,decltype()、sizeof()和许多依赖编译时类型信息的其他函数变得无用。这是至关重要的事情,被修复。
首先,我们需要找出如何制作方便的类型/类型别名来为我们生成具有指定维度的数组类型?
单词类型表明它需要编译时间,最好的(可能是唯一的)方法是模板元编程。
其方法如下:我们采用一个类型和一个维度序列(例如,int, 3, 4, 5),并从末尾开始,将每个维度附加到该类型。
#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递归在到达一维情况时停止,并在返回的过程中追加其他维度。数组的分配非常简单:
new generate_dimensions_t<int, 3, 4, 5>;如果您想推迟构建,我们可以这样写:
operator new(sizeof(generate_dimensions_t<int, 3, 4, 5>));数组类型的大小是正确计算,这是我们的目标之一。
差不多就是这样了。保持冷静,拥抱C++。
发布于 2016-08-19 16:57:35
我需要分配T类型的n维数组,目前我正在使用以下函数.有更好的方法吗?
是。创建一个类来包装2/3D数组,以便以异常安全的方式正确地进行内存管理。
您可能需要与其他库进行接口的原始指针,但这并不意味着您应该积极地管理该指针。您需要将它们包装在一个类中,以便为您提供所有内存管理,但在需要时提供对原始指针的访问。
示例:
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
template <class T, class Ti>
T*** allocate_3d_array(Ti nx, Ti ny, Ti nz){在我看来,这始终是一个整数类型。选一个。如果您这样做是出于某种特定的原因,而我还没有推断,那么应该在代码的注释中指出这一点(如果对我来说不太明显,那么我认为没有其他人理解它)。
使用零初始化。
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]();https://codereview.stackexchange.com/questions/139156
复制相似问题