【问题标题】:What is boost's shared_ptr(shared_ptr<Y> const & r, T * p) used for?boost 的 shared_ptr(shared_ptr<Y> const & r, T * p) 是做什么用的?
【发布时间】:2010-11-27 01:41:19
【问题描述】:

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

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

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

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()

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

【问题讨论】:

  • 好问题。 +1
  • TL;DR 版本:它创建一个指向 r 的子对象的指针。

标签: c++ boost shared-ptr smart-pointers


【解决方案1】:

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

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

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

他们共享使用次数和内容。这是内存使用的优化。

【讨论】:

  • 一个很好的答案。显然,在这个例子中,只要有b 存在,我们就希望保留a 的对象。我认为我们有一个赢家。
  • 不仅是对内存使用的优化,而且在具体的例子中,使用不同的方法最终会调用delete( a-&gt;B ),这可能是意外的(考虑struct A { int b; }; shared_ptr&lt;A&gt; a(new A); shared_ptr&lt;int&gt; b( a, &amp;a-&gt;b )
  • 这不仅仅是内存使用的优化。它可能还有其他用途;)请参阅下面的答案..
【解决方案2】:

为了扩展 leiz'spiotr's 的答案,shared_ptr&lt;&gt; 'aliasing' 的描述来自 WG21 论文 "Improving shared_ptr for C++0x, Revision 2"

三。别名支持

高级用户通常需要 能够创建shared_ptr 与共享所有权的实例p 另一个(主)shared_ptrq 但是 指向一个不是基础的对象 的*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 );

效果:构造一个存储pshared_ptr实例并r共享所有权。

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

抛出:什么都没有。

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

[注意: 这个构造函数允许创建一个 empty shared_ptr 具有非 NULL 存储指针的实例。 --结束注释。]

【讨论】:

    【解决方案3】:

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

    class A {};
    class B: public A {};
    
    shared_ptr<A> a(new B);
    shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
    

    【讨论】:

    • 另一个有趣的用途,显然属于“别名”类别。好点子。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我已经在我的小库中使用了 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!
      

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

      【讨论】:

        【解决方案6】:

        对于“shared_ptr&lt;B&gt; b(a, dynamic_cast&lt;B*&gt;(a.get()));

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

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

        shared_ptr<B> b(a);
        

        由于在 Boost 文档中提到:

        shared_ptr&lt;T&gt; 可以隐式 每当 T* 转换为 shared_ptr&lt;U&gt; 可以隐式转换为 U*。在 特别是,shared_ptr&lt;T&gt; 是 隐式转换为shared_ptr&lt;T&gt; const, 到 shared_ptr&lt;U&gt; 其中 U 是 T 的可访问基数,以及 shared_ptr&lt;void&gt;.

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-12-06
          • 1970-01-01
          • 1970-01-01
          • 2017-10-22
          • 2013-07-21
          • 2018-02-19
          • 1970-01-01
          • 2013-09-24
          相关资源
          最近更新 更多