用指针包装器抽象所有权

时间:2017-12-28 17:03:20

标签: c++ smart-pointers

我希望自动魔术所有权处理我传递给另一个对象的依赖项。

这意味着如果通过原始指针引用依赖项,则不应该进行所有权转移,但如果它通过unique_ptr引用,则依赖项应该由我传入的对象管理。

为了支持这一点,我想在底层指针类型中使用类型擦除。我想出的东西似乎有效,但我不确定这是否真的是正确的方法。所以我的问题是:这是好的还是有其他/更好的模式。

template <typename T>
struct UberPtr
{
    UberPtr(T* v) : tag(POINTER), ptr(v) {}

    UberPtr(std::unique_ptr<T>&& v) : tag(UNIQUE_PTR), uPtr(std::move(v)) {}

    UberPtr(std::shared_ptr<T> v) : tag(SHARED_PTR), sPtr(v) {}

    UberPtr(UberPtr<T>&& other)
    {
        tag = other.tag;

        if (other.tag == UNIQUE_PTR)
        {
            std::swap(uPtr, other.uPtr);
        }
        else if (other.tag == SHARED_PTR)
        {
            std::swap(sPtr, other.sPtr);
        }
        else
        {
            std::swap(ptr, other.ptr);
        }

        other.tag = POINTER;
    }

    ~UberPtr()
    {
        if (tag == UNIQUE_PTR)
        {
            uPtr.get_deleter()(uPtr.get());
        }
        else if (tag == SHARED_PTR)
        {
            sPtr.~shared_ptr();
        }
    }

    T& operator*() const
    {
        if (tag == POINTER)
        {
            return *ptr;
        }
        else if (tag == UNIQUE_PTR)
        {
            return *uPtr;
        }
        else
        {
            return *sPtr;
        }
    }

    T* operator->() const
    {
        if (tag == POINTER)
        {
            return ptr;
        }
        else if (tag == UNIQUE_PTR)
        {
            return uPtr.get();
        }
        else
        {
            return sPtr.get();
        }
    }

private:
    enum {POINTER,UNIQUE_PTR,SHARED_PTR} tag;
    union
    {
        T* ptr;
        std::unique_ptr<T> uPtr;
        std::shared_ptr<T> sPtr;
    };

};

template <typename T>
auto make_uber(T&& t, std::enable_if_t<not std::is_pointer_v<T>>* = nullptr)
{
    UberPtr<typename std::remove_reference_t<T>::element_type> uberPtr(std::forward<T>(t));
    return uberPtr;
}

template <typename T>
auto make_uber(T t, std::enable_if_t<std::is_pointer_v<T>>* = nullptr)
{
    UberPtr<typename std::remove_pointer_t<T>> uberPtr(t);
    return uberPtr;
}

请注意我std::variant之前的原因,这就是为什么我在这里使用一个好的旧联盟。

编辑,因为评论中提到了这一点:

我知道deref的额外分支成本。在我的测试中(仅限clang),所有内容都被正确内联,同一个上下文中的多个derefs被优化掉,因此这个分支是我见过的唯一额外开销。

我想要使用的是无法了解所有权的库类。我见过的API经常提供方法重载,使用布尔值&#34;拥有&#34;支持这一点的参数以及明显需要进行分支的参数。

所以这个问题不是关于性能影响,而是更多,如果我可以得到与std类相似的东西。

0 个答案:

没有答案