Which smart pointer type?
我对智能指针的使用还比较陌生,我想确保不会引入坏习惯。我有一个从工厂创建并添加到队列中的对象A。然后从另一个线程读取该队列,此时我认为使用唯一的指针是完全有效的。
1 2 3 4 5 6 7 8 9 10 11
| struct IInterface
{
}
class A : public IInterface
{
}
std::queue<std::unique_ptr<A>> queue; |
然而,在构造A的时候,我意识到我需要一个C.C类,它包含一个B类的列表。
1 2 3 4 5 6 7 8 9 10 11 12 13
| class A : public IInterface
{
C c;
}
class B
{
}
class C
{
List<unqiue_ptr> b;
} |
对我来说,这看起来还可以,因为我们已经定义了所有权。但是,我不确定当类B现在需要一个指向iInterface的指针时需要使用什么指针,而a型恰好实现了这一点。我要把它变成一个共享资源吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| struct IInterface
{
}
class A : public IInterface
{
C c;
}
std::queue<std::shared_ptr<A>> queue;
class B
{
shared_ptr<IInterface> a;
}
class C
{
List<unique_ptr> b;
} |
我是否选择了正确的智能指针,我是否正确地分析了它?我知道这对你们来说非常简单,但我想在我开始做错事之前我会问。
- 为什么C存储unique_ptr而不是B?
- 工厂类/函数通常应该返回std::unique_prt。如果这是所有调用方都需要的,那么它是完美的。如果调用者需要共享所有权,他们只需将返回值存储在std::shared_ptr中,然后就可以得到它。
- @NeilButterworth的例子是面向智能指针,而不是公共/私有继承。你说得很好,所以我会更新以便澄清。
- 参见萨特在C++中的言论泄露自由…默认情况下
- 当你拥有某物时,使用std::unique_ptr;观察某物的原始指针;当你需要重新设计时,使用std::shared_ptr。
- @RichardCritten,如果我只是观察的话,使用一个参照物不是更好吗?
- @塔兹廷戈视情况而定。如果您在一个对象中存储一些东西,我通常会推荐指针而不是引用,因为引用不能反弹,所以如果您使用它们,就不能复制对象。
- 好吧,冷静点,这些答案很有帮助。你们真是太好了!@贾斯汀,我来看看你上传的视频,谢谢。
- @塔兹廷戈的问题是关于指针-参考也有用。
- 无关:std::queue应该是相当安全的,但是在围绕库容器内容的指针构建许多基础结构之前,请确保熟悉迭代器的失效规则。
- 还不清楚为什么需要任何指向B的指针。
- @Juanchopanza指向b的指针在那里,因为c拥有b,并被手动添加到它的列表中。添加它是为了复制我所面对的场景,而不需要所有的代码。这个问题更直接地指向A的指针。你确实帮助我解决了一些可能引起混淆的小问题,谢谢你的询问。
- @用户4581301:即使queue移动其元素(在给定非默认支持容器的情况下,它可能会移动),也不会使指向这些元素所指向对象的指针失效。
- 是啊。不知道我担心什么。
- @塔兹廷戈,这是没有理由有任何类型的指针。一些关键信息丢失了。或者你不需要指向B的指针。
抛开C通过指针拥有其B对象的原因,问题不在于A是否通过某些基类使用。实际上,即使Base具有非虚拟析构函数,也可以使用shared_ptr拥有派生类的对象!
真正的问题是,C拥有的B物体的寿命(可能与C的寿命相同)是否(已知)短于它们所指的A物体的寿命。如果是的话,你可以坚持使用unique_ptr拥有A和A*或IInterface*使用它们。如果没有,您应该考虑将shared_ptr用于两者,尽管您也应该考虑其他可能性,例如提前销毁单个B对象或将A的所有权转移到一个可以比观察到的参考资料更为长久的地方。
- 型你的意思是短于或等于寿命,然后使用唯一?我的一生恰巧是平等的。
- 型@塔兹廷戈:同时销毁两个对象是很少见的:唯一想到的情况是销毁一个没有析构函数的类型数组。但如果这能以某种方式发生,那就足够了。
- 型我想在我的例子中,A、B、C都是同时生成的,而A恰好被传入。一旦A被破坏,其他的就不再使用了。
- 型@塔兹廷戈:当然,不访问B::a(对于B类型的任何对象)就足够了(甚至可以将其与nullptr进行比较)。在公投被销毁后。我写了"更短的使用寿命"作为安全性的设计准则:如果您已经销毁了B,那么您就不可能太晚访问它的指针。