使用std :: unique_ptr的双(二维)数组

时间:2012-03-20 20:19:25

标签: c++ c++11 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。我在这里做错了什么?

8 个答案:

答案 0 :(得分:16)

您无法将int*分配给std::unique_ptr<int[]>,这是导致错误的原因。正确的代码是

      a[i] = std::unique_ptr<int[]>(new int[2]);

然而,piokuc是正确的,使用unique_ptr对数组是非常不寻常的,因为std::vectorstd::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<2, int>> container1(5); 
//make a 5x2 automatic array, can't resize the 2 or 5 but is _really fast_.
std::array<5, std::array<2, int>> container;

所有这些都可以初始化并使用与您已有的代码相同,除非它们更容易构建,并且您不必销毁它们。

答案 1 :(得分:5)

如果您没有使用std::arraystd::vector而不是动态分配的数组,可以在C +中使用unique_ptr作为二维数组+11如下:

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仿函数。

答案 2 :(得分:2)

您的代码正在有效地操作int数组数组。

在C ++中,您通常希望将其实现为:

std::vector<std::vector<int> > x;

这对unique_ptr来说不是一个好例子。此外,您不需要使用指向unique_ptr的指针并动态分配unique_ptr对象。 unique_ptr的重点是消除指针的使用并提供对象的自动分配和释放。

答案 3 :(得分:2)

for (i=0; i<5; i++)   // deallocation
      delete x[i];
  delete x;

否否否

delete [] x[i];
delete [] x;

//哟

答案 4 :(得分:1)

我可以想到使用std :: unique_ptr(或者说boost :: scoped_array)而不是std :: vector来保存数组的唯一原因通常是不适用的......

1)它可以节省1或2个指针的内存,具体取决于你是否知道所有数组的大小[不相关,除非你有大量非常小的数组]

2)如果你只是将数组传递给一个需要C样式数组或原始指针的函数,它可能感觉更自然。 std :: vector IS保证在顺序存储上,所以将(a.empty() ? nullptr : &a[0], a.size())传递给这样的函数也是100%合法的。

3)默认情况下,MSVC调试模式下的标准容器被“检查”并且非常慢,这对于在大型数据集上进行科学编程时可能会很烦人。

答案 5 :(得分:1)

#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]);
    }
}

答案 6 :(得分:0)

一个例子进一步激发了我对这个解决方案的启发

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 []。内存也以连续的方式分配,您可以轻松引入分配器,分配对齐的内存。

答案 7 :(得分:0)

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