动态分配带有智能指针的锯齿状阵列

时间:2013-07-12 19:08:04

标签: c++11 smart-pointers jagged-arrays

所以我最近熟悉(并爱上)boost和c ++ 11智能指针。它使内存管理变得更加容易。而且,最重要的是,它们通常仍然可以使用遗留代码(通过使用get调用)

然而,我一直遇到的大洞是多维锯齿状阵列。正确的方法是拥有boost::scoped_array<boost::scoped_array<double>>vector<vector<double>>,这将很好地清理。但是,您无法轻松地将double**发送到遗留代码。

有没有办法做到这一点,还是我坚持使用非智能锯齿状阵列?

2 个答案:

答案 0 :(得分:0)

如果您使用的是C ++ 11,则应该使用unique_ptr<T[]>而不是scoped_array<T>。它可以执行scoped_array可以执行的所有操作,然后执行一些操作。

如果你想要一个矩形阵列,我建议使用unique_ptr<double[]>来保存主数据,使用unique_ptr<double*[]>来保存行基。这将是这样的:

unique_ptr<double[]> data{ new double[5*3] };
unique_ptr<double*[]> rows{ new double*[3] };
rows[0] = data.get();
for ( size_t i = 1; i!=5; ++i )
    rows[i] = rows[i-1]+3;

然后,您可以将rows.get()传递给使用double**的函数。这种方法也适用于非矩形数组,前提是阵列的几何形状在数组创建时已知,这样您就可以一次分配所有数据并将rows指向正确的偏移量。 (但它可能不像简单的循环那么简单。)

这也将为您提供更好的参考和内存使用位置,因为您只执行两次分配。您的所有数据将一起存储在内存中,单独分配不会产生额外开销。

如果要在创建后更改锯齿状阵列的几何图形,则需要提供一种管理存储的原则方法,以使此解决方案适用。但是,由于使用scoped_array更改几何图形很笨拙(需要swap()的特定用途),如果这对您来说不是问题,我不会感到惊讶。

(请注意,此方法可以与scoped_array以及unique_ptr<[]>一起使用;我只是使用unique_ptr来说明它,因为我们现在在C ++ 11中。)< / p>

答案 1 :(得分:0)

我从std::vector<std::vector<double>>开始存储,除非结构是高度静态的。

要生成我的数组数组,我会通过转换上面的存储来生成std::vector<double*>,使用transform_to_vector( storage, []( std::vector<double>& v ) { return v.data(); } )transform_to_vector这样的语法作为练习给读者留下)。

保持两者同步只需将它包装在一个小类中即可。

如果锯齿状阵列的大小相对固定,我会用std::vector<std::size_t>创建我的缓冲区(或者std::initializer_list<std::size_t> - 实际上是template<typename Container>,而我d只需for( : )两次,然后让调用者选择它提供给我的容器,然后创建一个具有大小总和的std::vector<double>,然后在口述处构建一个std::vector<double*>偏移。

调整大小会变得很昂贵,这是一个缺点。

使用std::vector的一个不错的属性是,较新的API可以完全访问漂亮的beginend值。如果您有一个大缓冲区,则可以将子数组的范围视图暴露给新代码(包含double* begin()double* end()的结构,而我们在其中double& operator[]std::size_t size() const { return end()-begin(); }),这样他们就可以在C ++容器式视图中充分享受完全的荣耀,同时保持传统接口的C兼容性。