【问题标题】:Allocate multidimensional array using new使用 new 分配多维数组
【发布时间】:2013-03-15 13:56:21
【问题描述】:

当我使用new分配多维数组时,我是这样做的:

void manipulateArray(unsigned nrows, unsigned ncols[])
{
  typedef Fred* FredPtr;
  FredPtr* matrix = new FredPtr[nrows];

  for (unsigned i = 0; i < nrows; ++i)
    matrix[i] = new Fred[ ncols[i] ];

}

其中ncols[] 包含matrix 中每个元素的长度,nrows 包含matrix 中元素的数量。

如果我想填充matrix,那么我有

  for (unsigned i = 0; i < nrows; ++i) {
      for (unsigned j = 0; j < ncols[i]; ++j) {
        someFunction( matrix[i][j] );

但我正在阅读C++ FAQ,谁告诉我要非常小心。我应该先用NULL 初始化每一行。然后,我应该trycatch 为行分配。我真的不明白为什么这一切。我一直(但我刚开始)使用上面的代码以 C 风格初始化。

常见问题解答要我这样做

void manipulateArray(unsigned nrows, unsigned ncols[])
{
  typedef Fred* FredPtr;

  FredPtr* matrix = new FredPtr[nrows];

  for (unsigned i = 0; i < nrows; ++i)
    matrix[i] = NULL;

  try {
    for (unsigned i = 0; i < nrows; ++i)
      matrix[i] = new Fred[ ncols[i] ];

    for (unsigned i = 0; i < nrows; ++i) {
      for (unsigned j = 0; j < ncols[i]; ++j) {
        someFunction( matrix[i][j] );
      }
    }

  }
  catch (...) {
    for (unsigned i = nrows; i > 0; --i)
      delete[] matrix[i-1];
    delete[] matrix;
    throw;    // Re-throw the current exception
  }

}

1/ 总是如此谨慎地初始化是牵强附会还是非常合适?

2/ 他们这样做是因为他们处理的是非内置类型吗?代码是否与double* matrix = new double[nrows]; 相同(谨慎程度相同)?

谢谢

编辑

部分答案在next item in FAQ

【问题讨论】:

  • 专业提示:std::vector 之类的东西知道如何正确执行此操作。
  • @antitrust 要求使用低级解决方案,因此高级方法没有帮助。提示:一个新的可能会失败(内存不足)
  • 除非您需要引用单个行/列,否则具有一维向量和合适的两个索引访问的简单实现非常适合动态矩阵结构。
  • 只是一个小评论:catch 块中的删除循环应该删除所有分配的内存,包括matrix[0]。因此,循环应该修改为for (unsigned i = nrows; i >= 0; --i)
  • @JSQuareD 我在做delete[] matrix[i-1];i-1 对吧?

标签: c++ exception initialization try-catch new-operator


【解决方案1】:

如此小心的原因是,如果这些分配中的任何一个失败,或者如果 Fred 构造函数抛出异常,就会发生内存泄漏。如果您要在调用堆栈的较高位置捕获异常,则您分配的内存没有句柄,这就是泄漏。

1) 没错,但一般来说,如果您要费这么大劲来防止内存泄漏,您更愿意使用std::vectorstd::shared_ptr(等等)来为您管理内存。

2) 内置类型也是如此,但至少如果分配失败,将抛出的唯一异常是 std::bad_alloc

【讨论】:

  • 我认为需要对NULL 进行初始化,以防matrix[i] = new Fred[ ncols[i] ]; 不起作用。因为在for (unsigned i = nrows; i &gt; 0; --i) delete[] matrix[i-1]; 中删除NULL 是可以的,但不是未初始化的东西。对吗?
  • 完全正确,是的 - 未初始化的指针将具有不安全删除的垃圾值,但删除 NULL 是完全安全的。在开始做可能引发异常的事情之前,您需要将它们设置为 NULL,因为否则您不知道哪些指向您已分配的事物,哪些未初始化。
  • 另外,如果您使用的是新式编译器(支持新版本的标准,称为 C++11),则表示 null 的新方式是 nullptr。在现代 C++ 编程中不鼓励使用旧的说法 (NULL)。
【解决方案2】:

我认为这取决于目标平台和系统要求。如果安全是一个高优先级和/或如果你可以用完内存,那么不,这并不牵强。但是,如果您不太关心安全性,并且您知道您系统的用户将拥有充足的可用内存,那么我也不会这样做。

这与是否使用内置类型无关。常见问题解答解决方案是将指向行的指针清空,以便在发生异常时,仅删除已创建的那些行(而不是某些随机内存位置)。

也就是说,我只能赞同 R. Martinho Ferndandes 的评论,即您应该为此使用 STL 容器。管理自己的记忆既乏味又危险。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-25
    • 2013-02-23
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    相关资源
    最近更新 更多