我有一个基本实体类和派生类,如奶牛和鸡......
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智能指针正确管理内存。我现在正在做的事情,我的派生类生活的唯一地方是共享指针的向量,如...
vector<shared_ptr<Cow>>
vector<shared_ptr<Chicken>>
etc.
My Entity类负责管理任何两个实体之间的关系,无论它们是否具有相同类型。为此,它保留了一个看起来像......的关系对象列表。
class Relationship
{
weak_ptr<Entity> from;
weak_ptr<Entity> to;
etc....
}
我使用弱指针,因为牛或鸡可能会死亡,在这种情况下,他们与其他实体的关系应该变得无效。
所以这是我的问题。我将所有内容存储为派生类的共享指针,但我的Entity类中的所有代码都使用指向基类的弱指针。我有时经常需要将弱Entity指针转换为共享的Cow指针或将Cow指针共享转换为弱的Entity指针。
不知何故,我的代码允许我在上面的Entity类中的createRelationship(...)中的参数中传递shared_ptr对象。我不知道为什么编译,我想知道这样做是否有效。我应该手动将其转换为弱指针然后使用static_pointer_cast进行转换吗? (我问这个是因为我已经读到传递共享指针作为参数很慢,我担心它会继续)。
在另一个方向,有时我知道某些关系是在同一类型的两个实体之间。为了说明我的观点,需要从其父母那里继承其遗传学的小公牛:它通过其关系搜索以找到父子关系,然后获得对其父母的弱实体指针的访问。为了访问它们的遗传成员变量,它需要将这些弱指针强制转换为实体,以共享指向Cows的指针。我一直在使用weak_ptr.lock(),然后使用dynamic_pointer_cast来完成此任务。
这是执行这两个(反向相关)演员表的有效方式吗?任何一般性评论或参考资料都值得赞赏,因为我试图有效地使用这些指针。
答案 0 :(得分:3)
听起来你有三个主要问题:
weak_ptr
以使用其值时,是否有效存储shared_ptr
?weak_ptr<T>
构建shared_ptr<T>
?static_ptr_cast
或dynamic_pointer_cast
问题2是最简单的;正如Vaughn所提到的,weak_ptr
来自shared_ptr
的{{3}}。
问题1和3更加模糊。为了解决这个问题,请访问为什么您听说传递shared_ptr
的速度很慢。当您传递shared_ptr
的值时,它必须复制shared_ptr
,并且复制它涉及基础引用计数的原子增量。这种原子增量有很多好处和缺点,但简短的版本是,如果你不需要跟踪所有权,这是一个不必要的开销。 (在大多数情况下担心这可能是过早的优化,但C ++语言希望确保在有必要的时候让你担心这类事情。)
复制weak_ptr
怎么样 - 比复制shared_ptr
更快?我还没有运行任何基准测试,但我猜不会。实际上有两个引用计数,一个用于拥有引用(shared_ptr
个副本)和非拥有(weak_ptr
个副本)。其中每个都具有相同的原子更新要求,因此不会明显更快。我在理论上认为weak_ptr
的析构函数不得不检查结果引用计数并删除对象,因此如果你所做的只是复制,那么这就少了一个分支。但这不太可能;您有机会通过shared_ptr
转换回lock()
。
这使我们回到问题1的核心。从观察shared_ptr
获得weak_ptr
需要多少开销?大约与复制shared_ptr
的原子引用计数一样多,加上您在消费代码上要求的分支以确保它成功,或在失败时处理。因此,不考虑效率,而是考虑所有权和对象生命周期。您是否会遇到lock()
将返回空shared_ptr
的情况?如果没有,很有可能你可以使用观察原始指针。如果基础shared_ptr
对象可能在weak_ptr
之前消失,则您需要对其进行过期检查。如果这是一个瓶颈,看看你是否找不到保证生命周期的方法。
最后回到问题3.我在这里回答时没有真正了解这些类型;相反,我的基础是shared_ptr
的工作方式。每个static_pointer_cast
,dynamic_pointer_cast
和const_pointer_cast
返回shared_ptr
个实例,指向同一个底层对象。因此,他们已经执行了其引用计数的原子增量。因此,它们的开销大致是静态或动态或const转换加上shared_ptr
复制构造函数的开销。 shared_ptr
部分不太可能对您的整体计划和铸造部分有重要影响,只有dynamic_cast
的{{1}}可能会产生可衡量的费用(静态和const转换几乎完全是编译时操作)。
因此,我们又一次回到了所有权和对象的生命周期。如果您拥有明确的所有权并且能够为您提供所需的生命周期,并且如果您还要编写处于性能瓶颈的代码,那么您将更加满意dynamic_pointer_cast
并观察原始指针(以及#39;很好;&#34;规则&#34;不是拥有原始指针)。但是,如果它不是瓶颈,或者对象的生命周期不容易保证,unique_ptr
和shared_ptr
绝对是方便,只需要尽可能小的成本来保证它们的语义。< / p>