我一直在使用pimpl习语制作一些对象,但我不确定是使用std::shared_ptr
还是std::unique_ptr
。
我理解std::unique_ptr
效率更高,但对我来说这不是一个问题,因为这些对象无论如何都相对较重,因此std::shared_ptr
的费用高于std::unique_ptr
是相对较小的。
由于额外的灵活性,我目前正在使用std::shared_ptr
。例如,使用std::shared_ptr
允许我将这些对象存储在散列映射中以便快速访问,同时仍然能够将这些对象的副本返回给调用者(因为我相信任何迭代器或引用都可能很快变得无效)。
然而,这些对象确实没有被复制,因为更改会影响所有副本,所以我想知道可能使用std::shared_ptr
并允许复制是某种反模式或坏事。 / p>
这是对的吗?
答案 0 :(得分:36)
我一直在使用pimpl习语制作一些对象,但我不确定是使用
shared_ptr
还是unique_ptr
。
绝对是unique_ptr
或scoped_ptr
。
Pimpl
不是一种模式,而是一种成语,它处理编译时依赖性和二进制兼容性。它不应该影响对象的语义,特别是关于它的复制行为。
你可以使用你想要的任何类型的智能指针,但那些2保证你不会意外地在两个不同的对象之间共享实现,因为它们需要有意识地决定复制构造函数和赋值的实现操作
然而,这些对象确实没有被复制,因为更改会影响所有副本,所以我想知道可能使用
shared_ptr
并允许复制是某种反模式或坏事。 / p>
它不是反模式,事实上,它是一种模式:别名。您已经在C ++中使用它与裸指针和引用。 shared_ptr
提供额外的“安全”措施,以避免死引用,代价是额外的复杂性和新问题(谨防造成内存泄漏的周期)。
与Pimpl无关
我理解
unique_ptr
效率更高,但对我来说这不是一个问题,因为这些对象无论如何都相对较重,因此shared_ptr
超过unique_ptr
的成本是相对较小。
如果您可以分解某些状态,您可能需要查看Flyweight模式。
答案 1 :(得分:10)
如果您使用shared_ptr
,那么它并不是真正的传统pimpl
成语(除非你采取额外的步骤)。但真正的问题
这就是你想要使用智能指针开始的原因;非常好
明确delete
应该发生的地方,并且没有问题
例外安全或其他需要关注的问题。最多,
一个智能指针将为您节省一两行代码。而且
只有一个具有正确语义的是boost::scoped_ptr
,
在这种情况下,我认为它不起作用。 (IIRC,它要求
一个完整的类型,以便实例化,但我可以
错了。)
pimpl习语的一个重要方面是它的用途应该是 对客户透明;该类应该表现得如同 它是经典实施的。这意味着要么禁止 复制和分配或实施深层复制,除非上课 是不可变的(没有非const成员函数)。没有通常的 智能指针实现深拷贝;你可以实现一个 当然,但它可能仍然需要一个完整的类型 每当副本发生时,这意味着你仍然需要 提供用户定义的复制构造函数和赋值运算符 (因为它们不能内联)。鉴于此,它可能不是 值得使用智能指针。
例外情况是对象是不可变的。在这种情况下,它
副本是否深入并不重要,shared_ptr
完全处理这种情况。
答案 2 :(得分:5)
当您使用shared_ptr
时(例如在容器中,然后查找并按按值返回),您不会导致它指向的对象的副本,只是带引用计数的指针的副本。
这意味着如果您从多个点修改基础对象,则会影响同一实例上的更改。这正是它的设计目标,所以不是一些反模式!
当传递shared_ptr
时(如评论所述),最好通过const引用并在需要时复制(通过递增引用计数)。至于返回,逐案。
答案 3 :(得分:1)
是的,请使用它们。简单地说,shared_ptr是智能指针的实现。 unique_ptr是自动指针的实现: