C++ 使用变量+;参考包装+;表示(非)拥有资源的想法的唯一\u ptr

C++ 使用变量+;参考包装+;表示(非)拥有资源的想法的唯一\u ptr,c++,c++17,C++,C++17,如果我需要表达这样的想法: 有一个场景节点(带有变换)可以指向(不拥有)几何体(例如网格), 但有时节点拥有几何体非常方便。 用这种方式表达这个想法可以吗?如果没有,你能谈谈如何表达这个想法吗 struct Node { variant<reference_wrapper<SceneObject>, unique_ptr<SceneObject>> sceneObject{nullptr}; }; Node node1; node1.sceneObj

如果我需要表达这样的想法: 有一个场景节点(带有变换)可以指向(不拥有)几何体(例如网格), 但有时节点拥有几何体非常方便。 用这种方式表达这个想法可以吗?如果没有,你能谈谈如何表达这个想法吗

struct Node
{
    variant<reference_wrapper<SceneObject>, unique_ptr<SceneObject>> sceneObject{nullptr};
};

Node node1;
node1.sceneObject = make_unique<Mesh>(); // node is responsible for the life of the mesh

Node node2;
node2.sceneObject = sceneObjectDatabase.getResource("myMesh"); //the node does not own the mesh, but simply references it

Node node3;
node3.sceneObject = nullptr; // doesn't own any geometry
struct节点
{
变体场景对象{nullptr};
};
节点1;
node1.sceneObject=make_unique();//节点负责网格的生命周期
节点2;
node2.sceneObject=sceneObjectDatabase.getResource(“myMesh”)//节点不拥有网格,但仅引用它
节点3;
node3.sceneObject=nullptr;//不拥有任何几何体

我不喜欢您特定示例中的
变体,即直接访问成员的简单结构。尽管它为您提供了所有权方面的灵活性,但这种灵活性会渗透到
Node::sceneObject
的每次使用中

变量是特殊所有权语义的实现细节。它应该与
sceneObject
的使用分离,因为所有权不是调用方关心的问题。然而,对于
变体
解决方案,它是紧密耦合的,因为调用者必须为拥有和不拥有
场景对象
s做不同的事情

我喜欢@n.m.与自定义删除器一起使用
unique\u ptr
的想法。它为您提供了所有权灵活性和访问
sceneObject
的一致方式。添加一个
make\u-owning\u-sceneObject()
和一个
make\u-non\u-owning\u-sceneObject()
函数,您就有了一个漂亮而简单的API。
此外,该解决方案似乎对性能的影响最小。访问始终是通过指针的简单间接寻址,根本没有
变量
机制。当然,关于未测量性能推测的常见警告适用。

这里不要使用变体。你没有不同的类型,你只有一个类型,但只有一个该类型的属性。所以你可以写一个可能拥有的类型,基本上是一个
T*
和一个
bool

template <typename T>
class maybe_owning_ptr {
    T* ptr_;
    bool owns_;

public:
    maybe_owning_ptr() : ptr_(nullptr), owns_(false) { }
    maybe_owning_ptr(T* p, bool owns) : ptr_(p), owns_(owns) { }
    ~maybe_owning_ptr() {
        if (owns_) delete ptr_;
    }

    maybe_owning_ptr(maybe_owning_ptr&& rhs) noexcept
        : ptr_(std::exchange(rhs.ptr_, nullptr))
        , owns_(std::exchange(rhs.owns_, false))
    { }

    maybe_owning_ptr& operator=(maybe_owning_ptr&& rhs) noexcept
    {
        T* p = std::exchange(rhs.ptr_, nullptr);
        bool o = std::exchange(rhs.owns_, false);

        if (owns_) delete ptr_;
        ptr_ = p;
        owns_ = o;
        return *this;
    }

    // accessors here... get(), operator*, operator->(), etc.
};
模板
类可能\u拥有\u ptr{
T*ptr;
布尔拥有,;
公众:
可能是:ptr(nullptr),owns(false){
也许,拥有,拥有:拥有,拥有
~z~也许_拥有_ptr(){
如果(拥有)删除ptr;
}
可能拥有(可能拥有)不例外
:ptr_(std::exchange(rhs.ptr_,nullptr))
,owns_u2;(std::exchange(rhs.owns_2;,false))
{ }
可能拥有的ptr&operator=(可能拥有的ptr&rhs)不例外
{
T*p=std::exchange(rhs.ptr,nullptr);
bool o=std::exchange(rhs.com,false);
如果(拥有)删除ptr;
ptr=p;
拥有uo=o;
归还*这个;
}
//这里的访问器…get()、运算符*、运算符->()等。
};
请注意,我们不能有一个复制构造函数——因为在我们拥有所有权的场景中,我们不知道该做什么


总是想用某物……/p>这不是太多C++标签吗?也许是<代码> STD::SyrdYPPTR 是你正在寻找的,我想。对我来说不是太方便。我会用一个定制的删除器来探索一个独特的\u ptr。带有不可操作删除器的唯一\u ptr类似于非拥有指针。@n.m.这一点很好,但我认为在这种情况下,查看该类的用户会认为该节点拥有该资源。您可以将自定义唯一\u ptr键入类似于可选\u拥有\u ptr的内容。是的,
std::exchange
是整洁的:)用于复制构造函数,如果我们拥有,那么我们就不能调用基础类型的复制构造函数吗?是的,如果基础类型没有复制构造函数,我们可能需要解决这个问题。我喜欢std::variant,因为它消除了实现这些特殊成员函数的需要。它还使用值语义,不强制您使用堆。