'new' 和 'delete' 在 C++ 中被弃用了吗?

Are 'new' and 'delete' getting deprecated in C++?

我偶然发现了一个涉及不同大小的数组声明的测验。我想到的第一件事是我需要使用 new 命令进行动态分配,如下所示:

while(T--) {
   int N;
   cin >> N;
   int *array = new int[N];
   // Do something with 'array'
   delete[] array;
}

但是,我看到其中一种解决方案允许以下情况:

while(T--) {
    int N;
    cin >> N;
    int array[N];
    // Do something with 'array'
}

经过一番研究后,我了解到 g++ 允许这样做,但这让我一直在思考,在哪些情况下有必要使用动态分配?还是编译器将其翻译为动态分配?

包括删除功能。但是请注意,这里的问题与内存泄漏无关。

您的第二个示例使用 variable length arrays (VLAs), which are actually a C99 (not C++!) feature, but nonetheless supported by g++

另见

请注意,可变长度数组与 new/delete 不同,并且不要以任何方式 "deprecate" 它们。

另请注意,VLA 不是 ISO C++。

嗯,首先,new/delete 不会被弃用。

不过,在您的具体情况下,它们并不是唯一的解决方案。您选择什么取决于您的 "do something with array" 评论下隐藏的内容。

你的第二个例子使用了一个非标准的 VLA 扩展,它试图让数组适合堆栈。这有一定的局限性——即大小有限,并且在数组超出范围后无法使用此内存。你不能将它移出,它会在堆栈展开后 "disappear"。

因此,如果您的唯一目标是进行本地计算,然后丢弃数据,它实际上可能工作正常。然而,更稳健的方法是动态分配内存,最好使用 std::vector。这样你就可以根据运行时值(这是我们一直在做的)为你需要的元素创建 space,但它也会很好地自我清理,而且你如果您想保留内存供以后使用,可以将其移出此范围。

回到开头,vector 可能会用到 new 更深的几层,但你不必担心,因为它呈现的界面要好得多。从这个意义上讲,可以认为不鼓励使用 newdelete

您显示的两个片段都不是惯用的现代 C++ 代码。

newdelete(以及 new[]delete[])在 C++ 中没有被弃用,而且永远不会被弃用。它们仍然是 实例化动态分配对象的方式。但是,由于您必须始终匹配 newdelete(以及 new[]delete[]),因此最好将它们保存在(库)类 为您确保这一点。参见 Why should C++ programmers minimize use of 'new'?

您的第一个代码段使用 "naked" new[],然后从不 delete[] 创建数组。那是个问题。 std::vector 可以满足您的一切需求。它将在幕后使用某种形式的 new(我不会深入探讨实现细节),但对于您必须关心的所有内容,它是一个动态数组,但更好更安全。

您的第二个片段使用了 "variable length arrays" (VLAs),这是一个 C 特性,一些 编译器也允许在 C++ 中作为扩展。与 new 不同,VLA 本质上是在堆栈上分配的(非常有限的资源)。但更重要的是,它们不是标准的 C++ 功能,应该避免使用,因为它们不可移植。它们当然不会取代动态(即堆)分配。

第一个例子最后需要一个delete[],否则会发生内存泄漏。

第二个例子使用了C++不支持的可变数组长度;它只允许数组长度的常量表达式

在这种情况下,使用 std::vector<> 作为解决方案很有用;它将您可以对数组执行的所有操作包装到模板中 class.

现代 C++ 提供了更简单的方法来处理动态分配。一旦引用的数据结构超出范围,智能指针可以在异常(如果允许的情况下可能发生在任何地方)和早期 returns 之后进行清理,因此使用它们可能是有意义的:

  int size=100;

  // This construct requires the matching delete statement.
  auto buffer_old = new int[size];

  // These versions do not require `delete`:
  std::unique_ptr<int[]> buffer_new (new int[size]);
  std::shared_ptr<int[]> buffer_new (new int[size]); 
  std::vector<int> buffer_new (size);  int* raw_access = buffer_new.data();

从 C++ 14 开始,您还可以编写

auto buffer_new = std::make_unique<int[]>(size);

这看起来更好,并且可以在分配失败时防止内存泄漏。从 C++ 20 开始,您应该可以做

auto a = std::make_shared<int[]>(size);

这对我来说在使用 gcc 7.4.0 编写时仍然无法编译。在这两个示例中,我们也使用 auto 代替左侧的类型声明。在所有情况下,照常使用数组:

buffer_old[0] = buffer_new[0] = 17;

内存泄漏 new 和双倍 delete 崩溃是 C++ 多年来一直受到抨击的问题,成为切换到其他语言的争论 "central point"。也许最好避免。

语法看起来像 C++,但惯用语类似于普通的老式 Algol60。像这样的代码块很常见:

read n;
begin
    integer array x[1:n];
    ... 
end;

例子可以写成:

while(T--) {
    int N;
    cin >> N;
    {
        int array[N];
        // Do something with 'array'
    }
}

我有时会想念当前语言中的这个 ;)

newdelete 没有被弃用。

new操作符创建的对象可以通过引用传递。 可以使用 delete 删除对象。

new 和 delete 是语言的基础方面。 可以使用 new 和 delete 来管理对象的持久性。 这些绝对不会被弃用。

语句 - int array[N] 是一种定义数组的方法。该数组可以在封闭代码块的范围内使用。它不能像对象传递给另一个函数那样传递。