使用shared_ptr获得唯一所有权(有点)——这是一种好的做法吗
Using shared_ptr for unique ownership (kind of) - is this good practice?
这很难解释,但我会尽力的。因此,我有一个RenderComponent、EventManager和RenderSystem。在我的RenderComponents构造函数中,我引发了RenderSystem订阅的renderComponentCreated事件。使用事件args对象,我传递一个RenderNode作为数据,其中包含RenderSystem绘制东西所需的信息(可绘制、位置和类型)。
到目前为止还不错。现在,当renderComponent被删除时,我希望RenderNode自动从RenderSystem中删除,同时仍然保留手动删除它的选项,例如作为对某个事件的反应。这可以使用RenderComponent RemoveNodeEvent来完成,RenderSystem再次订阅该事件。
现在是"问题"。根据我的理解(以及我想要的),renderNode应该是RenderComponent唯一拥有的东西(因此是unique_ptr)。但是,这将需要复制(并为renderNode-->实现一个比较运算符,以便在要删除它时能够找到它)或将引用/原始指针传递给renderNode。然而,(如果我是正确的)没有办法知道引用是否仍然引用了一个有效的对象,这意味着无法实现自动删除。
我的解决方案是使RenderNode(由RenderComponent唯一拥有)共享并向事件传递弱指针。RenderSystem现在还维护一个弱指针列表,检查它们是否仍指向有效对象,如果不指向,则自动删除它们。所以本质上,我想要的是从一个唯一的指针创建一个弱指针。然而,按照现在的方式,有人可以从弱指针创建一个共享指针,并使RenderNode的活动时间比它应该的更长。由于托管对象本身(RenderNode)包含对其他对象的引用,这些对象的存在时间不会超过RenderComponent,这可能会导致严重问题。
我现在的问题是:这是一个好的设计吗?还是我错过了什么?
附言:很抱歉,如果这个解释读起来有点笨拙(英语不是我的母语),谢谢你的帮助!
使用std::weak_ptr
授予对可能被破坏的对象的访问权限肯定没有错,这就是它的发明目的。但它确实需要对象本身由std::shared_ptr
保持。这不仅掩盖了由其父对象控制对象生存期的意图,还强制动态分配对象,并阻止它成为父对象的成员变量。
另一种方法是通过句柄跟踪指针,并有一个句柄管理器来跟踪对象是活的还是死的。实现这一点最安全的方法是将管理器作为您正在跟踪的对象的基类,这样RAII可以确保它始终是最新的。以下是该概念的示例实现。注:未经测试。
template<class Derived>
class HandleBased
{
public:
typedef uint64_t handle_t;
HandleBased() : m_Handle(NextHandle())
{
Map()[m_Handle] = this;
}
~HandleBased()
{
auto it = Map().find(m_Handle);
Map().erase(it);
}
handle_t ThisHandle()
{
return m_Handle;
}
static Derived* FindPtr(handle_t h)
{
auto it = Map().find(h);
if (it == Map().end())
return null_ptr;
return static_cast<Derived*>(it->second);
}
private:
static handle_t NextHandle()
{
static handle_t next = 0;
return next++;
}
static std::unordered_map<handle_t, HandleBased*>& Map()
{
static std::unordered_map<handle_t, HandleBased*> the_map;
return the_map;
}
handle_t m_Handle;
};
这里有一个如何使用它的例子:
class RenderNode : public HandleBased<RenderNode>
{
};
class RenderComponent
{
std::unique_ptr<RenderNode> node1;
RenderNode node2;
public:
void Setup(RenderSystem& rs)
{
node1 = new RenderNode;
rs.nodes.push_back(node1->ThisHandle());
rs.nodes.push_back(node2.ThisHandle());
}
};
class RenderSystem
{
public:
std::list<RenderNode::Handle> nodes;
void DoRender()
{
for (auto it = nodes.begin(); it != nodes.end(); )
{
RenderNode* p = RenderNode::FindPtr(*it);
if (p == NULL)
it = nodes.erase(it);
else
{
p->DoSomething();
++it;
}
}
}
};
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 有没有一种方法可以在编译时获得作用域类名
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 一种在C++中读取TXT配置文件的简单方法
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在调用接收数组的方法时,模板化数组大小是不是一种糟糕的做法
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- 在 c++ 中,有一种方法可以创建一个包含地图作为值的树状地图?
- 有没有一种优雅而快速的方法来测试整数中的 1 位是否位于连续区域
- 在运行时检查继承是否只有一种类型和 void*
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 使用shared_ptr获得唯一所有权(有点)——这是一种好的做法吗
- c++是唯一一种使用mpi的语言吗
- 是否有一种方法可以安全地删除指向MyObject的非唯一指针的QList