我一直在使用粉刺习语制作一些对象,但我不确定是否使用std::shared_ptr
或std::unique_ptr
。
我知道std::unique_ptr
更有效,但这对我来说不是什么大问题,因为这些对象相对重量级,所以std::shared_ptr
比std::unique_ptr
的成本相对较小。
我目前正在与std::shared_ptr
只是因为额外的灵活性。例如,使用std::shared_ptr
允许我将这些对象存储在hashmap中以便快速访问,同时仍然能够将这些对象的副本返回给调用者(因为我相信任何迭代器或引用都可能很快失效)。
然而,这些对象在某种程度上确实没有被复制,因为更改会影响所有副本,所以我想知道也许使用std::shared_ptr
并允许复制是某种反模式或坏事。
正确吗?
我一直在使用粉刺习语制作一些对象,但我不确定是否使用
shared_ptr
或unique_ptr
。
肯定是unique_ptr
或scoped_ptr
。
Pimpl
不是模式,而是处理编译时依赖关系和二进制兼容性的习惯用法。它不应该影响对象的语义,特别是关于它的复制行为。
你可以在底层使用任何你想要的智能指针,但它们保证你不会意外地在两个不同的对象之间共享实现,因为它们需要有意识地决定复制构造函数和赋值操作符的实现。
然而,这些对象在某种程度上确实没有被复制,因为更改会影响所有副本,所以我想知道也许使用
shared_ptr
并允许复制是某种反模式或坏事。
它不是一个反模式,事实上,它是一个模式:混叠。在c++中,您已经使用了裸指针和引用。shared_ptr
提供了额外的"安全"措施,以避免死引用,代价是额外的复杂性和新问题(注意产生内存泄漏的循环)。
与粉刺无关
我知道
unique_ptr
更有效,但这对我来说不是什么大问题,因为这些对象相对重量级,所以shared_ptr
相对于unique_ptr
的成本相对较小。
如果你可以提出一些状态,你可能想看看Flyweight模式。
如果你使用shared_ptr
,它就不是真正的经典粉刺习语(除非您采取额外的步骤)。但真正的问题是这就是为什么你要用一个智能指针开始;这是非常明确delete
应该发生在哪里,并且没有问题异常安全或其他需要关注的问题。最多智能指针将为您节省一两行代码。和只有一个语义正确的是boost::scoped_ptr
,我不认为这在本案中起作用。(IIRC,它要求一个完整的类型,以便实例化,但我可以错了。)
青春痘习语的一个重要方面是它的使用应该是对客户透明;类的行为应该完全像它被经典地实现了。这意味着要么抑制复制和赋值或实现深度复制,除非类不可变(没有非const成员函数)。不像平常那样智能指针实现深度复制;你可以实现一个当然,但它可能仍然需要一个完整的类型当复制发生时,也就是说你仍然需要提供用户定义的复制构造函数和赋值操作符(因为它们不能内联)。考虑到这一点,它可能不是值得使用智能指针。
异常是指对象不可变。在这种情况下,它复制是否深度无关紧要,shared_ptr
当您使用shared_ptr
(例如在容器中,然后查找并返回按值)时,您不会复制它所指向的对象,而只是复制带有引用计数的指针。
这意味着如果您从多个点修改底层对象,那么您将影响到同一实例上的更改。这正是它的设计目的,所以不是一些反模式!
当传递shared_ptr
(如注释所说)时,最好通过const引用传递,并在需要的地方复制(通过增加引用计数)。
是的,请使用它们。简单地说,shared_ptr是一个智能指针的实现。Unique_ptr是一个自动指针的实现: