26

boost::shared_ptr有一个不寻常的构造函数

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);

我有点困惑这会有什么用。基本上它共享所有权r,但.get()会返回p r.get()

这意味着您可以执行以下操作:

int main() {
    boost::shared_ptr<int> x(new int);
    boost::shared_ptr<int> y(x, new int);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

你会得到这个:

0x8c66008
0x8c66030
2
2

请注意,指针是分开的,但它们都声称 ause_count为 2(因为它们共享同一对象的所有权)。

因此,只要int存在,所拥有的就会存在。如果我理解文档正确,第二个永远不会被破坏。我已经通过以下测试程序确认了这一点:xx yint

struct T {
    T() { std::cout << "T()" << std::endl; }
    ~T() { std::cout << "~T()" << std::endl; }
};

int main() {
    boost::shared_ptr<T> x(new T);
    boost::shared_ptr<T> y(x, new T);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

这输出(如预期):

T()
T()
0x96c2008
0x96c2030
2
2
~T()

那么......这个不寻常的结构有什么用处,它共享一个指针的所有权,但在使用时就像另一个指针(它不拥有)。

4

6 回答 6

29

当您想要共享一个类成员并且该类的一个实例已经是一个 shared_ptr 时,它很有用,如下所示:

struct A
{
  int *B; // managed inside A
};

shared_ptr<A>   a( new A );
shared_ptr<int> b( a, a->B );

他们分享使用次数和东西。它是内存使用的优化。

于 2009-09-10T05:29:33.120 回答
8

为了扩展leizpiotr 的答案,对shared_ptr<>“别名”的描述来自 WG21 论文“Improving shared_ptrfor C++0x, Revision 2”

三、别名支持

高级用户通常需要能够创建与shared_ptr 另一个p(主)共享所有权shared_ptr q但指向的对象不是*q. *p例如,可以是 的成员或元素*q。本节提出了一个可用于此目的的附加构造函数。

这种表达能力增加的一个有趣的副作用是现在*_pointer_cast可以在用户代码中实现这些功能。本 make_shared文档后面介绍的工厂函数也可以仅使用shared_ptr通过别名构造函数的公共接口来实现。

影响:

此功能以向后兼容的方式扩展了接口 shared_ptr,增加了其表达能力,因此强烈建议将其添加到 C++0x 标准中。它没有引入源代码和二进制兼容性问题。

建议案文:

shared_ptr 将以下构造函数添加到[util.smartptr.shared]:

template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );

将以下内容添加到 [util.smartptr.shared.const]:

template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );

效果:构造一个shared_ptr实例来存储p共享所有权 r

后置条件: get() == p && use_count() == r.use_count() .

抛出:什么都没有。

[注意:为避免出现悬空指针的可能性,此构造函数的用户必须确保p至少在所有权组r被销毁之前保持有效。——结束注。]

[注意:此构造函数允许 使用非 NULL 存储指针创建一个空实例。 ——结束注。]shared_ptr

于 2009-09-10T05:39:23.947 回答
4

您还可以使用它来保持动态转换的指针,即:

class A {};
class B: public A {};

shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
于 2010-08-11T11:00:10.860 回答
2

您可能有一个指向某个驱动程序或较低级别 api 的数据结构的指针,这些数据结构可以通过其较低级别的 api 或其他方式分配额外的数据。在这种情况下,增加 use_count 可能会很有趣,但如果第一个指针拥有其他数据指针,则返回附加数据。

于 2009-09-10T05:32:29.540 回答
0

对于“ shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));

我认为这不是使用智能指针的推荐方式。

进行这种类型转换的推荐方法应该是:

shared_ptr<B> b(a);

由于在 Boost 文档中提到:

shared_ptr<T>shared_ptr<U>只要 T* 可以隐式转换为 U*,就可以隐式转换为。特别是,shared_ptr<T>可以隐式转换为shared_ptr<T> constshared_ptr<U>其中 U 是 T 的可访问基数,以及 shared_ptr<void>

除此之外,我们还有dynamic_pointer_cast 可以直接对智能指针对象进行转换,这两种方法都比手动转换原始指针方式安全得多。

于 2011-01-14T11:25:38.357 回答
0

我在我的小库中使用了 shared_ptr 的别名构造函数:

http://code.google.com/p/infectorpp/(只是我的简单 IoC 容器)

关键是因为我需要从多态类(不知道类型)返回一个已知类型的 shared_ptr 。我无法将 shared_ptr 隐式转换为我需要的类型。

在文件“ InfectorHelpers.hpp ”(第 72-99 行)中,您可以看到 IAnyShared 类型的操作。

别名构造函数创建 shared_ptr 不会删除它们实际指向的指针,但它们仍然会增加原始对象的引用计数器,这非常有用。

基本上,您可以使用别名构造函数创建指向任何内容的指针,并将其作为引用计数器。

//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress

virtual std::shared_ptr<int> getReferenceCounter(){
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}

virtual void* getPtr(); //return raw pointer to T

现在我们有“一个引用计数器”和一个指向 T 的 istance 的指针,足够的数据可以用别名构造函数创建一些东西

std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter 
               static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!

我并不假装发明了别名构造函数的这种用法,但我从未见过其他人这样做。如果您猜测该脏代码是否有效,答案是肯定的。

于 2013-07-13T16:11:28.533 回答