如果我需要表达这样的想法: 有一个场景节点(带有变换)可以指向(不拥有)几何体(例如网格), 但有时节点拥有几何体非常方便。 以这种方式表达这个想法是否可以?如果没有 - 你能否就如何表达这个想法提出一些想法?
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
答案 0 :(得分:2)
我不喜欢variant
在您的特定示例中,即在一个可以直接访问成员的简单结构中。虽然它为您提供了所有权的灵活性,但这种灵活性会渗透到Node::sceneObject
的每次使用中。
变体是特殊所有权语义的实现细节。它应该与sceneObject
的使用分离,因为所有权不是调用者的关注点。然而,variant
解决方案紧密耦合,因为调用者必须为拥有和非拥有sceneObject
做不同的事情。
我喜欢@n.m的想法。将unique_ptr
与自定义删除器一起使用。它为您提供了所有权的灵活性和访问sceneObject
的一致方式。添加make_owning_sceneObject()
和make_non_owning_sceneObject()
函数,您就拥有了一个简单的API。
此外,该解决方案似乎对性能处罚的可能性最小。访问始终是通过指针的简单间接,根本没有variant
机制。当然,关于未测量的性能推测的常见警告适用。
答案 1 :(得分:2)
此处不要使用变体。你没有不同的类型,你有一种类型 - 但只有一种类型的属性。所以你可以写一个可能拥有的类型,基本上是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.
};
请注意,我们不能拥有复制构造函数 - 因为我们不知道在拥有所有权的场景中该怎么做。
一直想用std::exchange()
来表达某些事情......