实施 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