在C++中,delete和delete[]是两个不同的操作符。delete用于删除通过new运算符分配的单个对象,而delete[]用于删除通过new[]运算符分配的数组对象。当使用delete操作符删除一个数组对象时,行为是未定义的,可能会导致内存泄漏或程序崩溃。因此,在删除数组对象时应该使用delete[]操作符,以确保正确释放内存。
在C++中,我们使用delete
和delete[]
运算符来释放动态分配的内存。这两个运算符的使用是有区别的,delete
用于释放单个对象的内存,而delete[]
用于释放数组对象的内存。
具体来说,当我们使用new
运算符分配一个数组对象时,编译器会根据数组大小来调用相应数量的构造函数来创建对象。例如,当我们使用new ABC[100]
来分配一个包含100个ABC对象的数组时,编译器会调用100次构造函数来创建对象。
然而,如果我们简单地使用delete ptr
来释放这个数组对象的内存,编译器将不知道ptr
指向的是一个包含多少个对象的数组,因此只会调用一个析构函数并删除1个对象的内存,导致了内存泄漏。因此,在这种情况下,我们需要使用delete [] ptr
来释放内存,以确保调用正确数量的析构函数并删除所有对象的内存。
需要注意的是,在C语言中是没有析构函数的概念的,因此我们只需要使用free()
来释放内存,而不需要考虑调用析构函数。如果我们使用伪析构函数模式,需要使用for
循环来依次调用析构函数。
总结一下,delete
用于释放单个对象的内存,而delete[]
用于释放数组对象的内存。在C++中,如果我们错误地混用这两个运算符,会导致程序不合法。编译器可能知道需要调用多少个析构函数,也可能不知道。如果使用错误,编译器可以选择中止程序并告诉我们问题所在。
在C++中,使用delete[]
运算符删除数组,使用delete
运算符删除非数组对象。它们分别调用operator delete[]
和operator delete
函数来删除数组或非数组对象占用的内存,在删除之前(最终)调用数组元素或非数组对象的析构函数。
delete[]
运算符和delete
运算符的关系如下所示:
typedef int array_type[1]; // 创建并销毁一个int[1]数组 array_type *a = new array_type; delete [] a; // 创建并销毁一个int int *b = new int; delete b; // 创建并销毁一个int[1]数组 int *c = new int[1]; delete[] c; // 创建并销毁一个int[1][2]数组 int (*d)[2] = new int[1][2]; delete [] d;
对于使用new
创建数组(即new type[]
或new
应用于数组类型构造)的情况,标准会在数组元素类型类或全局范围内寻找operator new[]
,并传递请求的内存量。如果需要,它可能请求超过N * sizeof(ElementType)
的内存,例如用于存储元素的数量,以便在删除时知道需要调用多少个析构函数。如果类声明了一个operator new[]
,该函数除了接受内存量外,还接受另一个size_t
参数,该参数将接收分配的元素数量,可以根据需要使用它(例如调试等)。
对于使用new
创建非数组对象的情况,它会在对象的类或全局范围内寻找operator new
。它传递请求的内存量(始终是sizeof(T)
)。
对于delete[]
,它会查找数组元素的类类型并调用它们的析构函数。使用的operator delete[]
函数是元素类型类中的函数,如果没有则在全局范围内查找。
对于delete
,如果传递的指针是实际对象类型的基类,那么基类必须有一个虚析构函数(否则行为是未定义的)。如果它不是一个基类,那么将调用该类的析构函数,并使用该类或全局operator delete
。如果传递了一个基类,那么将调用实际对象类型的析构函数,并使用该类中找到的operator delete
,如果没有找到,则调用全局operator delete
。如果类中的operator delete
具有第二个类型为size_t
的参数,则它将接收要释放的元素数量。
如果我有一个指向对象的指针数组,其中每个指针可能为nullptr,那么delete[]
不会删除这些指针指向的对象,对吗?delete[]
只会删除嵌入在数组中的数组元素。例如,如果你有一个结构体数组,那么每个结构体的析构函数都会被调用。但是如果你有一个指向结构体的指针数组,那么指针所占用的内存将被释放,但是指针指向的任何结构体的内存将不会被释放。
在C++中,delete
操作符释放内存并调用通过new
创建的单个对象的析构函数。
delete[]
操作符释放内存并调用通过new[]
创建的对象数组的析构函数。
在指向new[]
返回的指针上使用delete
,或在指向new
返回的指针上使用delete[]
会导致未定义的行为。
我想知道在使用delete
删除一个包含原始类型(如int或char)的new[]
数组时,是否也会导致未定义的行为。因为使用原始类型时,似乎并没有存储数组大小的地方。
如果标准没有定义这样做时会发生什么,那么根据定义,这就是"未定义的行为",即使你的编译器会以你期望的方式确定性地执行。另一个编译器可能会执行完全不同的操作。
当我有一个类似"char** strArray"的C字符串数组时,我犯了这个错误。如果你有一个和我一样的数组,你需要遍历数组并删除/释放每个元素,然后删除/释放strArray本身。在我所拥有的数组上使用"delete[]"是行不通的,因为(正如上面的评论和答案所指出的),它会调用析构函数,而不是实际释放每个槽位。