C++ C++;11智能指针的所有权和铸造

C++ C++;11智能指针的所有权和铸造,c++,shared-ptr,software-design,weak-ptr,C++,Shared Ptr,Software Design,Weak Ptr,我有一个基本实体类和派生类,比如cows和Ficks using namespace std; class Entity { list<shared_ptr<Relationship>> relationships; void createRelationship(weak_ptr<Entity> other,.... other stuff) //... virtual ~Entity() } class Cow: publi

我有一个基本实体类和派生类,比如cows和Ficks

using namespace std;
class Entity
{
    list<shared_ptr<Relationship>> relationships;
    void createRelationship(weak_ptr<Entity> other,.... other stuff)
    //...
    virtual ~Entity()
}
class Cow: public Entity
{
    //...
}
class Chicken : public Entity
....etc...
使用名称空间std;
类实体
{
列出关系;
无效创建关系(弱\u ptr其他,…其他内容)
//...
虚拟实体()
}
类别:公共实体
{
//...
}
类别:公共实体
等
我正在努力学习使用std智能指针正确管理内存。我现在的工作方式是,我的派生类唯一存在的地方就是共享指针的向量,比如

vector<shared_ptr<Cow>>
vector<shared_ptr<Chicken>>
etc.
向量
矢量
等
我的实体类负责管理任意两个实体之间的关系,无论它们是否具有相同的类型。为此,它保留了一个关系对象列表,这些对象看起来像

class Relationship
{
  weak_ptr<Entity> from;
  weak_ptr<Entity> to;
etc....
}
类关系
{
弱ptr来自;
弱ptr至;
等
}
我使用弱指针是因为牛或鸡可能会死亡,在这种情况下,它们与其他实体的关系将变得无效

这就是我的问题。我将所有内容存储为指向派生类的共享指针,但实体类中的所有代码都使用指向基类的弱指针。我经常需要将弱实体指针转换为共享Cow指针,或者将共享Cow指针转换为弱实体指针

不知何故,我的代码允许我在上面实体类的createRelationship(…)中的参数中传递共享的\u ptr对象。我真的不知道为什么会编译,我想知道这样做是否有效。我是否应该手动将其转换为弱指针,然后使用static\u pointer\u cast进行强制转换?(我问这个问题是因为我读到将共享指针作为参数传递很慢,我担心会发生这种情况)

在另一个方向,有时我知道某些关系是在同一类型的两个实体之间。为了说明我的观点,一头需要从父母那里继承其遗传基因的小牛:它搜索其关系以找到父子关系,然后访问指向其父母的弱实体指针。为了访问它们的遗传成员变量,它需要将这些指向实体的弱指针转换为指向奶牛的共享指针。我一直在使用弱\u ptr.lock()和动态\u指针\u强制转换来实现这一点


这是执行这两个(反向相关)强制转换的有效方法吗?任何一般性的评论或参考资料都是值得赞赏的,因为我正试图有效地使用这些指针

听起来你有三个主要顾虑:

  • 当您必须频繁转换为共享的
    以使用其值时,存储
    弱的\u ptr
    是否有效
  • 为什么您可以从
    共享的\u ptr
    构建
    弱的\u ptr
  • 使用
    静态\u ptr\u cast
    动态\u指针\u cast
  • 问题2是最简单的;正如沃恩所提到的,
    弱ptr
    有一个from
    共享ptr

    问题1和3更加模糊。为了解决这个问题,让我们来看看为什么您听说传递
    shared\u ptr
    很慢。当您通过值传递
    shared_ptr
    时,它必须复制
    shared_ptr
    ,复制它涉及基础引用计数的原子增量。这种原子增量有很多好处和坏处,但简短的版本是,如果您不需要跟踪所有权,这是一种不必要的开销。(在大多数情况下,担心这可能是过早的优化,但是C++语言希望确保在必要时你能担心这种事情。) 复制一个
    弱的\u ptr
    ——这比复制一个
    共享的\u ptr
    快吗?我还没有运行任何基准测试,但我想不会。实际上有两个引用计数,一个用于拥有引用(
    shared_ptr
    copies),另一个用于非拥有引用(
    weak_ptr
    copies)。其中每一个都有相同的原子更新要求,因此速度不会明显加快。理论上,我猜想
    弱ptr
    的析构函数不必检查结果引用计数并删除对象,因此如果您所做的只是复制,那么就少了一个分支。但这是一个不太可能的用法;您很可能会通过
    lock()
    转换回
    共享的\u ptr

    这让我们回到问题1的核心。从观察的
    弱的
    获取
    共享的
    有多少开销?大约相当于复制
    共享的\u ptr
    的原子引用计数,加上您需要在消费代码上执行的分支,以确保它成功,或在失败时处理它。因此,与其考虑效率,不如考虑所有权和对象寿命。您是否曾经遇到过这样的情况:
    lock()
    将返回一个空的
    shared\u ptr
    ?如果不是这样的话,你很可能会用一个观察不到的指针逃脱惩罚。如果基础
    共享\u ptr
    对象可能在
    弱\u ptr
    之前消失,则需要对其进行过期检查。如果这是一个瓶颈,看看你是否能找到一种方法来保证生命周期

    最后回到问题3。我在这里回答这些问题时,并没有真正了解这些类型;相反,我是基于
    共享ptr
    的工作原理。每个
    static\u pointer\u cast
    dynamic\u pointer\u cast
    const\u pointer\u cast
    返回指向同一底层对象的
    共享\u ptr
    实例。因此,他们执行了其参考计数的原子增量。因此,它们的开销大致相当于静态、动态或常量转换加上
    共享\u ptr
    复制构造函数的开销。
    shared_ptr
    部分不太可能对您的整个计划有重要意义,而在铸造部分,只有