[英]Double (two-dimensional) array using std::unique_ptr
我有一个由指向指针的指针分配的双数组。
// pointer to pointer
int **x = new int *[5]; // allocation
for (i=0; i<5; i++){
x[i] = new int[2];
}
for (i=0; i<5; i++){ // assignment
for (j=0; j<2; j++){
x[i][j] = i+j;
}
}
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
我正在尝试使用unique_ptr
来做到这一点:
std::unique_ptr<std::unique_ptr<int>[]> a(new std::unique_ptr<int>[5]);
for (i=0; i<5; i++)
a[i] = new int[2];
但一直收到错误消息,说no operator = matches these operands
。 我在这里做错了什么?
您不能将int*
分配给std::unique_ptr<int[]>
,这是导致错误的原因。 正确的代码是
a[i] = std::unique_ptr<int[]>(new int[2]);
但是, piokuc 是正确的,将unique_ptr
用于数组是非常不寻常的,因为这就是std::vector
和std::array
的用途,具体取决于是否提前知道大小。
//make a 5x2 dynamic jagged array, 100% resizable any time
std::vector<std::vector<int>> container1(5, std::vector<int>(2));
//make a 5x2 dynamic rectangular array, can resize the 5 but not the 2
std::vector<std::array<int, 2>> container1(5);
//make a 5x2 automatic array, can't resize the 2 or 5 but is _really fast_.
std::array<std::array<int, 2>, 5> container;
所有这些都可以像您已有的代码一样进行初始化和使用,只是它们更容易构建,而且您不必销毁它们。
如果您没有使用std::array
或std::vector
而不是动态分配的数组的奢侈,您可以在 C++11 中为二维数组使用unique_ptr
,如下所示:
std::unique_ptr<int*, std::function<void(int**)>> x(
new int*[10](),
[](int** x) {
std::for_each(x, x + 10, std::default_delete<int[]>());
delete[] x;
}
);
unique_ptr
声明负责分配数组的行维度。 new int*[10]()
的尾随()
确保每个列指针都初始化为nullptr
。
然后 for 循环分配列数组:
for (size_t row = 0; row < 10; ++row) {
(x.get())[row] = new int[5];
}
当unique_ptr
超出范围时,其自定义删除器 lambda 函数会在删除行数组之前处理删除列数组。 for_each
表达式使用default_delete函子。
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
不不不不
delete [] x[i];
delete [] x;
//哟
我能想到的在 std::vector 上使用 std::unique_ptr(或说 boost::scoped_array)来保存数组的唯一原因通常不适用......
1)它节省了 1 或 2 个指针的内存,这取决于您是否知道所有数组的大小[无关,除非您有大量非常小的数组]
2) 如果您只是将数组传递给某个需要 C 样式数组或原始指针的函数,它可能会感觉更自然。 尽管 std::vector 保证在顺序存储上,因此将(a.empty() ? nullptr : &a[0], a.size())
给这样的函数也是 100% 合法的。
3) MSVC 调试模式下的标准容器默认被“检查”并且非常慢,这在对大型数据集进行科学编程时可能会很烦人。
#include <iostream>
#include <memory>
#define print(x) std::cout << x
#define println(x) std::cout << x << std::endl
int main() {
std::unique_ptr<std::unique_ptr<int[]>[]> arr(new std::unique_ptr<int[]>[2]());
for (int i = 0; i < 2; i++)
{
arr[i] = std::make_unique<int[]>(5);
for (int j = 0; j < 5; j++) {
arr[i][j] = j;
println(arr[i][j]);
}
println(arr[i]);
}
}
您的代码正在有效地操作 int 数组的数组。
在 C++ 中,您通常希望将其实现为:
std::vector<std::vector<int> > x;
这不是unique_ptr
的好例子。 此外,您不需要使用指向unique_ptr
指针并动态分配unique_ptr
对象。 unique_ptr
的全部意义在于消除指针的使用并提供对象的自动分配和解除分配。
进一步的一个例子启发了我这个解决方案
size_t k = 10;
std::unique_ptr<int*, std::function<void(int**)>> y(new int*[k](),
[](int** x) {delete [] &(x[0][0]);
delete[] x;});
// Allocate the large array
y.get()[0] = new int[k*10];
// Establish row-pointers
for (size_t row = 0; row < k; ++row) {
(y.get())[row] = &(y.get()[0][0]);
}
在这里,所有维度都可以是动态的,您可以将其包装在一个类中并公开一个 operator[]。 此外,内存以连续方式分配,您可以轻松引入分配器,该分配器分配对齐的内存。
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
这是一个常见的错误。 x[i] 是一个数组,因此您必须首先使用 delete[] 删除每个数组,然后您可以使用 delete[] 删除 int* 数组
正确的解除分配是:
for (i=0; i<5; i++)
delete[] x[i]; //desallocate each array of int
delete[] x; //desallocate your array of int*
x = nullptr; //good practice to be sure it wont cause any dmg
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.