什么时候需要删除C样式的数组?

dew*_*rde 3 c++ arrays

我在阅读另一个问题的绝佳答案,给出了以下具体示例:

char[] array = {'a', 'b', 'c', '\0'};
Run Code Online (Sandbox Code Playgroud)
Thing* t = new Thing[size];
t[someindex].dosomething();

Run Code Online (Sandbox Code Playgroud)

我评论说,作为一种好的做法,您应该添加delete[]第二个示例,因为这是人们忘记导致内存泄漏的位。

但是我不记得您是否需要delete[]一开始。我不认为您会这样做,因为没有,new所以它在堆栈中,但是我不是100%确信那是正确的。

ruo*_*ola 9

我不认为您会这样做,因为没有新功能,因此已经在堆栈中,但是我不确定100%正确。

当在array函数内部定义时,此推理是正确的,因此位于堆栈上。你必须永远不会使用delete在已经在栈上创建,无需使用任何对象newdelete在堆栈上使用分配的对象将导致未定义的行为。

char[] array = {'a', 'b', 'c', '\0'};但是,如果定义出现在文件范围内,则它将具有静态存储持续时间,并且不会在堆栈上,但是仍然不会被动态分配,并且仍然不能被定义delete[]

因此,无论哪种方式,都不要delete[]使用数组。


klu*_*utt 7

  1. 您始终且仅delete在使用过newdelete[]使用过时使用new[]。切勿混合。切勿与(2)混用。
  2. 您总是且仅free在进行经典C分配(例如malloc或)时使用calloc。切勿与(1)混用。但是不要释放分配给alloca;)的内存

请注意,在某些情况下,分配或取消分配可以隐藏在函数之内。例如,有一个非标准C函数的那份像这样的字符串:char *str = strdup("Hello");。在这种情况下,free(str)即使您没有手动调用,也应该使用malloc

因此,如果您在表单上声明,T t[10]或者T[] t={a,b,c}不取消分配它。

int main()
{
    int x;
    std::cin << x;

    T *a = new T;
    delete a;
    T *b = new T[x];
    delete[] b;
    T *c = (T*)malloc(x*sizeof(*c));
    free(c);

    // No free or delete for these
    T d;
    T e[10];
    // Assuming a, b and c are instances of T or that you have overloaded the
    // operator so that you can write T t=a; 
    // In either case, you should not free nor delete this
    T f[] = {a, b, c};
}
Run Code Online (Sandbox Code Playgroud)

在C语言中,您可以使用VLA:s,例如在编译时不知道int arr[x]where x。这在C ++中是不可能的。您也不在这些阵列上使用免费。

我不认为您会这样做,因为没有新功能,因此已经在堆栈中,但是我不确定100%正确。

这是不正确的。该标准没有规定对象应该在堆栈还是堆上。这取决于编译器,因此实际发生的问题是编译器通常如何解决任务。

此外,大多数情况下,静态分配的内存最终出现在堆栈上而动态分配的内存最终出现在堆上的“事实”才是正确的。当然,通常会发生这种情况,但是在少数情况下却并非如此。而且这些情况并非罕见或模糊不清,因此可以忽略。全局变量通常不会最终出现在堆栈中。

因此,是否应该释放/删除内存并不是内存是否位于堆栈或堆中的问题。它是关于如何分配的。

而在现代C ++中你很少使用newnew[]deletedelete[]在所有。而是使用智能指针和容器。看一下此链接: 什么是智能指针,何时应使用它?以及https://en.cppreference.com/w/cpp/container/vector如果您正在处理旧的旧版C ++,将其重构为现代内存管理可能是一个好主意。如果将new- delete对更改为智能指针,则说明已保存一行。如果您更改new没有对应的delete,那么您已经解决了一个错误。

TL; DR

什么时候需要删除C样式的数组?

对于这种情况T a[n](带有或不带有初始化),您永远都不要这样做。对于这种情况,T *a = new T[n]您应该始终这样做。无论您何时使用过new,都应delete事后使用,永远不要用。(对此可能会有一些罕见的例外。请参阅本文的其余部分。)

同样,AFIK也没有“ C样式数组”的既定定义。就我个人而言,我根本不会考虑T *a = new T[n]使用数组。我也不会考虑T *a = malloc(n*sizeof(*a))数组。原因很简单。指针和数组不是一回事,对于C和C ++都是如此。这个问题与C有关,但也适用于C ++:数组名是指针吗?


Kit*_*it. 5

我评论说,作为一种好的做法,您应该在第二个示例中添加delete [],因为这是人们忘记导致内存泄漏的地方。

您还应该添加delete[]才能调用析构函数。除了释放一些内部分配的内存外,析构函数还可能具有其他副作用。

在语义上,newdelete(和new[]delete[])成对出现。new开始对象生存期,并delete结束由开始的对象生存期new。但是,通常建议将删除隐藏在智能指针中。

这个想法是将对象生存期绑定到“对象所有权”的概念。静态对象归整个程序所有。自动对象由定义它们的代码块拥有。动态对象在C ++语言本身中没有明确定义的所有权,尽管该语言为工具提供了实现代码编写者对象所有权概念的工具。

智能指针是这些工具之一。std::unique_ptr当对象在任何时候只有一个所有者时使用,但是您可能希望在代码块之间传递所有权。std::shared_ptr当可以有多个所有者时使用,并且当最后一个所有者停止对对象感兴趣时,对象生存期应结束。