所以我最近熟悉(并爱上)boost和c ++ 11智能指针。它使内存管理变得更加容易。而且,最重要的是,它们通常仍然可以使用遗留代码(通过使用get
调用)
然而,我一直遇到的大洞是多维锯齿状阵列。正确的方法是拥有boost::scoped_array<boost::scoped_array<double>>
或vector<vector<double>>
,这将很好地清理。但是,您无法轻松地将double**
发送到遗留代码。
有没有办法做到这一点,还是我坚持使用非智能锯齿状阵列?
答案 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可以完全访问漂亮的begin
和end
值。如果您有一个大缓冲区,则可以将子数组的范围视图暴露给新代码(包含double* begin()
和double* end()
的结构,而我们在其中double& operator[]
和std::size_t size() const { return end()-begin(); }
),这样他们就可以在C ++容器式视图中充分享受完全的荣耀,同时保持传统接口的C兼容性。