c++ 使用std::unique_ptr的双精度(二维)数组

3hvapo4f  于 2022-11-27  发布在  其他
关注(0)|答案(8)|浏览(260)

我有一个由指针到指针分配的双精度数组。

// 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。我在这里做错了什么?

b5lpy0ml

b5lpy0ml1#

不能将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<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;

所有这些都可以像您已经拥有的代码一样进行初始化和使用,只是它们更容易构造,而且您不必销毁它们。

wbrvyc0a

wbrvyc0a2#

如果您无法使用std::arraystd::vector来代替动态分配的数组,您可以在C++11中使用std::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声明负责分配数组的 row 维。new int*[10]()中的尾随()确保每个列指针都被初始化为nullptr
然后,for循环分配列数组:

for (size_t row = 0; row < 10; ++row) {
    (x.get())[row] = new int[5];
}

unique_ptr超出作用域时,它的自定义deleter lambda函数会在删除行数组之前先删除列数组。for_each表达式使用default_delete函子。

ajsxfq5m

ajsxfq5m3#

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

不不不不

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

//哟

4dbbbstv

4dbbbstv4#

我能想到的使用std::unique_ptr(或者说boost::scoped_array)而不是std::vector来保存数组的唯一原因通常是不适用的...
1)它节省了1或2个指针的内存,这取决于你是否知道所有数组的大小[除非你有大量非常小的数组,否则无关紧要]
2)如果你只是将数组传递到某个需要C风格数组或原始指针的函数中,这可能会让你感觉更自然。std::vector肯定是在顺序存储上,所以将(a.empty() ? nullptr : &a[0], a.size())传递到这样的函数中也是100%合法的。
3)MSVC调试模式中的标准容器默认情况下是“选中”的,速度非常慢,这在对大型数据集进行科学编程时可能会很烦人。

hivapdat

hivapdat5#

您的代码有效地操作了int数组的数组。
在C++中,您通常会希望将其实现为:

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

这对于unique_ptr来说不是一个好的例子。另外,你不需要使用指向unique_ptr的指针,也不需要动态地分配unique_ptr对象。unique_ptr的全部意义在于消除指针的使用,并提供对象的自动分配和释放。

yvfmudvl

yvfmudvl6#

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

pxyaymoc7#

更前面的一个例子启发了我这个解决方案

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

这里所有的维度都可以是动态的,你可以把它 Package 在一个类里面,并公开一个运算符[]。另外,内存是以连续的方式分配的,你可以很容易地引入一个分配器,它分配对齐的内存。

yshpjwxd

yshpjwxd8#

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

相关问题