我希望自动魔术所有权处理我传递给另一个对象的依赖项。
这意味着如果通过原始指针引用依赖项,则不应该进行所有权转移,但如果它通过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类相似的东西。