c++ make_shared<> 二维数组

c++ make_shared<> with 2d array

在处理2d数组分配时使用简单的指针是通过new以这种方式完成的(假设矩阵10x1000):

double ** dPtr ;
dPtr = new  double*  [10] ;
    for( size_t i =0 ; i<10 ; i++ ){
         dPtr[i] = new double [1000] ;
    }

现在,当使用智能指针时,我们可以定义矩阵类型(假设使用shared_ptr)为

std::shared_ptr<std::shared_ptr<double[]>[]> dPtr ;

如何使用 make_shared<> 执行相同分配的正确语法?

我不会多次调用 new,而是一次分配一个大缓冲区:double* array = new double[10 * 1000];。当然这取决于你想要什么样的数据结构。单个缓冲区将具有更好的缓存局部性并且可能更快,但这取决于您的要求。

此外,您正在做的是为矩阵中的每一行添加一个 shared_ptr - 这就是您想要的吗?用一个 shared_ptr 来管理整个矩阵可能会更好:

std::shared_ptr<double[]> array (new double[10*1000]);

如果你真的想要,你也可以在每一行中添加一个 shared_ptr:

std::shared_ptr<std::shared_ptr<double[]>[]> array2(
    new std::shared_ptr<double[]>[10]);
for (int i = 0; i < 10; i++)
{
    array2[i] = std::shared_ptr<double[]>(new double[1000]);
}

将您的代码直接翻译成 std::make_shared() 看起来像这样:

std::shared_ptr<std::shared_ptr<double[]>[]> dPtr;
dPtr = std::make_shared<std::shared_ptr<double[]>>(10);
for( size_t i = 0 ; i < 10 ; i++ ){
     dPtr[i] = std::make_shared<double[]>(1000);
}

可以进一步清理一下,例如:

using double_ptr_1D = std::shared_ptr<double[]>;
using double_ptr_2D = std::shared_ptr<double_ptr_1D[]>;

double_ptr_2D dPtr = std::make_shared<double_ptr_1D>(10);
for( double_ptr_1D &elem : dPtr ){
     elem = std::make_shared<double[]>(1000);
}

甚至:

using double_ptr_1D = std::shared_ptr<double[]>;

auto dPtr = std::make_shared<double_ptr_1D>(10);
for( auto &elem : dPtr ){
     elem = std::make_shared<double[]>(1000);
}

现在,话虽如此,直到 C++17 才将数组支持添加到 std::shared_ptr,直到 C++20 才添加到 std::make_shared()。因此,如果您使用的是 C++17,则必须使用 new[] 手动构建数组,例如:

using double_ptr_1D = std::shared_ptr<double[]>;
using double_ptr_2D = std::shared_ptr<double_ptr_1D[]>;

double_ptr_2D dPtr( new double_ptr_1D[10] );
for(size_t i = 0; i < 10; ++i){
    dPtr[i] = double_ptr_1D( new double[1000] );
}

但是,如果您使用的是 C++11 或 C++14,那么您就不走运了,因为您根本无法对数组使用 std::shared_ptrstd::unique_ptr 在 C++11 中具有数组支持,在 C++14 中 std::make_unique() 也是如此,但是 std::unique_ptr 没有 reference-counting 语义 std::shared_ptr 已。如果你真的需要它,你将不得不手动实现你自己的引用计数。