我正在实现类my_unique_ptr
和my_shared_ptr
,这些类模仿标准库智能指针std::unique_ptr
和std::shared_ptr
以更好地了解它。
在实现析构函数时,我很难决定是使用delete
还是delete[]
来释放内存。尽管我在 SO 和其他网站上读到了很多,但没有便携式方法来知道new[]
分配了多少字节(或者是否使用了new
或new[]
((新分配了多少字节?
在实现类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[]
使用它来正确释放内存。另请阅读"程序员有责任将new
与delete
匹配,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[] 删除它。