2009-09-10 79 views
26

boost::shared_ptr有着不同寻常的构造什么是boost的shared_ptr(shared_ptr <Y> const&r,T * p)用于?

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 

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

所以,通过x拥有的int会存在,只要xy周围。如果我理解文档正确,第二个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() 

所以......这是什么不寻常的结构的这股一个指针的所有权的有效性,但行为像使用时的另一个指针(它不拥有)。

+7

好问题。 +1 – GManNickG 2009-09-10 05:43:59

+3

TL; DR版本:它创建一个指向“r”子对象的指针。 – 2013-07-13 16:15:41

回答

29

当你想与大家分享类成员和类的一个实例,它是有用的已经是一个shared_ptr的,像下面这样:

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

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

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

+1

一个很好的答案。显然,在这个例子中,只要'b'在附近,我们就想保留'a'的对象。我认为我们有一个胜利者。 – 2009-09-10 18:54:19

+0

不仅对内存使用进行了优化,而且在具体的例子中,使用不同的方法最终会调用'delete(a-> B)',这可能是意想不到的(考虑struct A {int b;}; shared_ptr a(new A); shared_ptr b(a,&a-> b)') – 2010-03-16 13:48:12

2

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

8

为了扩展leiz'spiotr's答案,shared_ptr<> '混叠' 的描述是从WG21纸,"Improving shared_ptr for C++0x, Revision 2"

III。走样支持

高级用户往往需要创建一个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); 

影响:构造一个shared_ptr实例存储与rp股份所有权。

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

引发:什么也没有。

[注:为了避免悬空指针的可能性,此构造的用户 必须确保p仍然有效,至少 直到r所有权组被销毁。 - 注完]

[注:此构造允许shared_ptr 实例的创建与非NULL指针存储。 - 注完]

4

您也可以使用这种方式来保持动态铸造指针,即:

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

shared_ptr<A> a(new B); 
shared_ptr<B> b(a, dynamic_cast<B*>(a.get())); 
+0

另一个有趣的用途,显然属于“别名”的范畴。好点子。 – 2010-08-11 14:36:40

0

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

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

做这种类型的转换的推荐的方法应是:

shared_ptr<B> b(a); 

由于升压文献中,提到的是:

shared_ptr<T>可以隐 转换为shared_ptr<U>每当T * 可以被隐式转换为U *。在 特别地,shared_ptr<T>是 隐式转换为shared_ptr<T> const, 到shared_ptr<U>其中U是T的 访问的基础上,并 shared_ptr<void>

除此之外,我们也有dynamic_pointer_cast 这可能直接做智能指针对象无一不这两种方法的转换会比手工铸造的原料指针方式更安全。

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! 

我不想假装已经发明了这个用于别名构造函数,但我从来没有见过其他人在做同样的事情。如果你猜测这个脏代码是否有效,答案是肯定的。

相关问题