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,因为它消除了实现这些特殊成员函数的需要。它还使用值语义,不强制您使用堆。