如何知道何时在 C++ 中调用 delete 以及何时调用 delete[]?
How to know when to call delete and when delete[] in C++?
我正在实现模仿标准库智能指针 std::unique_ptr
和 std::shared_ptr
的 classes my_unique_ptr
和 my_shared_ptr
以更好地了解它。
在实现析构函数时,我很难决定是使用 delete
还是 delete[]
来释放内存。正如我在 SO 和其他网站上阅读的那样,没有 可移植的方式 知道 new[]
分配了多少字节(或者是否使用了 new
或new[]
) (How many bytes were allocated by new?)
在实现 class my_unique_ptr
时,我无法知道用户将从构造函数请求多少字节,即
他会不会my_unique_ptr<int> ptr1(new int)
或者他会做
my_unique_ptr<int> ptr1(new int[5])
如果有办法请告诉我!
这是我的 class(经过简化且没有 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[]
使用它来正确释放内存。另请阅读“程序员有责任将 new
与 delete
匹配,将 new[]
与 delete[]
匹配”。但是我如何在我的 class 中对此进行编程,以便它始终匹配正确的运算符?
旁注:
运行 valgrind
而在任何地方都使用 delete
而不是 delete[]
并传递超过 1 个 int
(比如 new int[5]
)我的构造函数 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
获得的内存进行初始化,my_unique_ptr<T[]>
必须使用从[=12获得的内存进行初始化=].这是您图书馆的用户必须遵守的合同。不尊重就是UB
通过提供 std::make_unique
. Also see
的等价物来帮助用户遵守本合同
Does this mean delete is successfully freeing all the 5 ints allocated by new[]
没有。在不是从 new
获得的内存上调用 delete
是 UB。
实际上,标准库智能指针比您的代码更方便,它们可以在调用析构函数时使用什么运算符(delete 或 delete[])。它们默认采用delete,如果你想使用delete[],你应该将它提供给智能指针构造函数。除此之外,如果您创建单个对象,请使用 new 和 delete。如果你创建一个数组,使用 new[] 来创建它,使用 delete[] 来删除它。
我正在实现模仿标准库智能指针 std::unique_ptr
和 std::shared_ptr
的 classes my_unique_ptr
和 my_shared_ptr
以更好地了解它。
在实现析构函数时,我很难决定是使用 delete
还是 delete[]
来释放内存。正如我在 SO 和其他网站上阅读的那样,没有 可移植的方式 知道 new[]
分配了多少字节(或者是否使用了 new
或new[]
) (How many bytes were allocated by new?)
在实现 class my_unique_ptr
时,我无法知道用户将从构造函数请求多少字节,即
他会不会my_unique_ptr<int> ptr1(new int)
或者他会做
my_unique_ptr<int> ptr1(new int[5])
如果有办法请告诉我!
这是我的 class(经过简化且没有 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[]
使用它来正确释放内存。另请阅读“程序员有责任将 new
与 delete
匹配,将 new[]
与 delete[]
匹配”。但是我如何在我的 class 中对此进行编程,以便它始终匹配正确的运算符?
旁注:
运行 valgrind
而在任何地方都使用 delete
而不是 delete[]
并传递超过 1 个 int
(比如 new int[5]
)我的构造函数 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
获得的内存进行初始化,my_unique_ptr<T[]>
必须使用从[=12获得的内存进行初始化=].这是您图书馆的用户必须遵守的合同。不尊重就是UB通过提供
的等价物来帮助用户遵守本合同std::make_unique
. Also see
Does this mean delete is successfully freeing all the 5 ints allocated by new[]
没有。在不是从 new
获得的内存上调用 delete
是 UB。
实际上,标准库智能指针比您的代码更方便,它们可以在调用析构函数时使用什么运算符(delete 或 delete[])。它们默认采用delete,如果你想使用delete[],你应该将它提供给智能指针构造函数。除此之外,如果您创建单个对象,请使用 new 和 delete。如果你创建一个数组,使用 new[] 来创建它,使用 delete[] 来删除它。