实施 unique_ptr:删除未分配的对象
Implementing unique_ptr: Deleting non-allocated objects
我的目标是实现 unique_ptr 的简单版本,它只提供构造函数、析构函数、->、* 和 release()。
但是,如果 unique_ptr 使用未分配的指针进行初始化,我不知道该怎么办。
例如
int i = 0;
unique_ptr<int> p{&i};
如果 unique_ptr 只是对其拥有的指针调用 delete,这将产生未定义(和不希望的)行为,至少据我所知是这样。我能做些什么来防止这种情况发生?
编辑:我对这个问题的尝试如下...
template<typename T>
class Uptr
{
public:
Uptr<T>(T* pt) : mp_owned{pt} {}
~Uptr<T>() {delete mp_owned;}
Uptr<T>(const Uptr<T>&) = delete;
Uptr<T>& operator=(const Uptr<T>&) = delete;
T& operator*() const {return *mp_owned;}
T* operator->() const {return mp_owned;}
T* release() {return mp_owned;}
private:
T* mp_owned;
};
您无法以编程方式检查指针值是如何获得的。在你的情况下(这是大部分真实编程的高度代表!),解决方案是记录你的接口到要求指针值可删除。您为您的用户设置了 前提条件,这要求您的用户阅读文档并遵循它,而您没有也不能提供语言内方法来验证这些前提条件。您将负担转嫁给您的用户。
这样的前置条件负担总是形成一种 "technical debt",你想尽可能地避免它(但也许不会以运行时成本为代价)。例如,在标准库中,我们强烈反对使用 unique_ptr
的所有权获取构造函数,而是作为用户使用 make_unique
,它没有先决条件并导致有效的 unique_ptr
值。该设计是您在现实世界中如何管理技术债务的典范。
不幸的是,您对此无能为力:对象的所有权必须转移到 unique_ptr<T>
,如果您使用全局、静态或自动区域中的对象地址,这是不可能的。
标准库中的实现,即 std::unique_ptr<T,Deleter>
,采用删除器参数,您可以使用该参数不删除任何内容。然而,这种用法是非常值得怀疑的,因为在这种情况下你根本不需要 unique_ptr
。
我的目标是实现 unique_ptr 的简单版本,它只提供构造函数、析构函数、->、* 和 release()。
但是,如果 unique_ptr 使用未分配的指针进行初始化,我不知道该怎么办。
例如
int i = 0;
unique_ptr<int> p{&i};
如果 unique_ptr 只是对其拥有的指针调用 delete,这将产生未定义(和不希望的)行为,至少据我所知是这样。我能做些什么来防止这种情况发生?
编辑:我对这个问题的尝试如下...
template<typename T>
class Uptr
{
public:
Uptr<T>(T* pt) : mp_owned{pt} {}
~Uptr<T>() {delete mp_owned;}
Uptr<T>(const Uptr<T>&) = delete;
Uptr<T>& operator=(const Uptr<T>&) = delete;
T& operator*() const {return *mp_owned;}
T* operator->() const {return mp_owned;}
T* release() {return mp_owned;}
private:
T* mp_owned;
};
您无法以编程方式检查指针值是如何获得的。在你的情况下(这是大部分真实编程的高度代表!),解决方案是记录你的接口到要求指针值可删除。您为您的用户设置了 前提条件,这要求您的用户阅读文档并遵循它,而您没有也不能提供语言内方法来验证这些前提条件。您将负担转嫁给您的用户。
这样的前置条件负担总是形成一种 "technical debt",你想尽可能地避免它(但也许不会以运行时成本为代价)。例如,在标准库中,我们强烈反对使用 unique_ptr
的所有权获取构造函数,而是作为用户使用 make_unique
,它没有先决条件并导致有效的 unique_ptr
值。该设计是您在现实世界中如何管理技术债务的典范。
不幸的是,您对此无能为力:对象的所有权必须转移到 unique_ptr<T>
,如果您使用全局、静态或自动区域中的对象地址,这是不可能的。
标准库中的实现,即 std::unique_ptr<T,Deleter>
,采用删除器参数,您可以使用该参数不删除任何内容。然而,这种用法是非常值得怀疑的,因为在这种情况下你根本不需要 unique_ptr
。