如何知道何时调用删除以及何时调用 delete[] C++?

How to know when to call delete and when delete[] in C++?

本文关键字:何时 调用 C++ delete 何知道 删除      更新时间:2023-10-16

我正在实现类my_unique_ptrmy_shared_ptr,这些类模仿标准库智能指针std::unique_ptrstd::shared_ptr以更好地了解它。

在实现析构函数时,我很难决定是使用delete还是delete[]来释放内存。尽管我在 SO 和其他网站上读到了很多,但没有便携式方法来知道new[]分配了多少字节(或者是否使用了newnew[]((新分配了多少字节?

在实现类my_unique_ptr时,我无法知道用户将从构造函数请求多少字节,即

他是否会做my_unique_ptr<int> ptr1(new int)

还是他会做my_unique_ptr<int> ptr1(new int[5])

如果有办法,请告诉我!

这是我的类(简化且没有 cpy/move 构造函数(:

template<typename ValueType>
class my_unique_ptr {
ValueType *internal_ptr = nullptr;
public:

// Default constructor
my_unique_ptr() {
internal_ptr = nullptr;
}
// Paramterized constructor
explicit my_unique_ptr(ValueType *ptr) {
if (ptr)
internal_ptr = ptr;
}
// Destructor
~my_unique_ptr() {

// How do I know whether to use
delete ptr;
// or
delete[] ptr;

}

我在某处读到编译器会跟踪new[]的参数,然后delete[]使用它来正确释放内存。另请阅读"程序员有责任将newdelete匹配,new[]delete[]相匹配"。但是我如何在我的类中对此进行编程,使其始终与正确的运算符匹配?

旁注:

在任何地方使用delete而不是delete[]在我的构造函数中传递超过 1int(比如用new int[5](时运行valgrind,Valgrind 说所有内存块都被释放了,没有泄漏的机会!(虽然显示像mismatched new[] with delete这样的警告。这是否意味着delete成功释放了new[]分配的所有 5 个ints?请帮忙。 我在Ubuntu 18.04并使用gcc 7.5.0.

您是对的,您无法知道内存是由new还是new[]分配的。但是你甚至不知道内存存储了一个自动持续时间的对象。例如,您的用户可以执行以下操作:

int a = 24;
my_unique_ptr<int> ptr1(&a); // oups

你没有办法知道这一点。因此,请执行标准库的功能:

  • 对数组类型进行专业化,例如template <class T> class my_unique_ptr<T[]>在析构函数上调用delete[]

  • 要求my_unique_ptr<T>必须使用从new获得的内存进行初始化,并且必须使用从new[]获得的内存初始化my_unique_ptr<T[]>。这是库用户必须遵守的合同。如果不尊重它,那就是 UB。

  • 通过提供等价物来帮助用户尊重本合同std::make_unique。另请参阅使用 std::make_unique 相对于新运算符的优势


这是否意味着删除成功释放了 new 分配的所有 5 个整数[]

不。在不是从new获得的内存上调用delete是 UB。

实际上,标准库智能指针比您的代码具有额外的功能,即它们能够在调用析构函数时使用什么运算符(delete 或 delete[](。默认情况下,它们采用删除,如果要使用 delete[],则应将其提供给智能指针构造函数。除此之外,如果创建单个对象,请使用 new 和 delete。如果创建一个数组,请使用 new[],使用 delete[] 删除它。