将shared_ptr转换为auto_ptr?

时间:2011-01-23 11:27:17

标签: c++ shared-ptr auto-ptr

我需要在我的代码中从shared_ptr获取auto_ptr。我可以做反向操作 - 将auto_ptr转换为shared_ptr,因为shared_ptr有这样的构造函数:

template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r);

我可以将shared_ptr转换为auto_ptr吗?或者设计不可能?

5 个答案:

答案 0 :(得分:9)

设计是不可能的,因为对象可能与其他共享指针共享,因此将其“提取”到auto_ptr可能会导致删除引用的对象。

出于同样的原因,shared_ptr没有“release”成员函数作为auto_ptr。

修改

即使shared_ptr有某种“释放”方法或允许删除它的引用 在不破坏对象的情况下,它不适用于以下情况(线程A,B):

A: { 
A:     int count = sp.use_count();
  Context Switch
B: shared_ptr<bar> my_sp = weak_sp.lock();
B: // now use_count = 2 but A thinks it is 1
  Context Switch
A:     auto_ptr<bar> ap;
A:     if(count == 1) 
A:      ap.reset(sp.release()); 
A:      // actutally there is no sp.release but what if
A:      ap->foo();
A: }  // delete the object pointer by ap as it goes out of scope
  Context Switch
B: my_sp->foo(); // Ooops - object is deleted!

答案 1 :(得分:4)

共享指针可以被很多东西共享,你不能以某种方式从它们中获取它。这由Artyompeoro详细说明。

一种方法是创建一个临时的auto_ptr,并将其从处理范围末尾的指针中释放出来。 dalle概述了第一种方法,但是这种方法缺少异常安全(可能会意外删除),并且它无法保护您不会意外地将其传递给将要转移所有权的功能(删除不属于我们的手)。

我们可以制作我们自己的包装器以避免这种情况:

template <typename T>
class auto_ptr_facade
{
public:   
    auto_ptr_facade(shared_ptr<T> ptr) :
    mPtr(ptr),
    mAuto(ptr.get())
    {}

    ~auto_ptr_facade()
    {
        // doesn't actually have ownership
        mAuto.release();
    }

    // only expose as const, cannot be transferred
    const auto_ptr<T>& get() const
    {
         return mAuto;
    }

    operator const auto_ptr<T>&() const
    {
         return get();
    }

private:
    auto_ptr_facade(const auto_ptr_facade&);
    auto_ptr_facade& operator=(const auto_ptr_facade&);

    shared_ptr<T> mPtr;
    auto_ptr<T> mAuto;
};

现在,您可以在范围内将shared_ptr视为const auto_ptr

template <typename T>
void foo(shared_ptr<T> ptr)
{
    auto_ptr_facade<T> a(ptr);

    // use a
}

答案 2 :(得分:3)

通常这是一个坏主意,因为auto_ptrshared_ptr都取得指针的所有权(他们会关心根据不同的政策销毁它和东西)。

让两个不同的对象持有相同指针的所有权可能会导致运行时错误,除非你为了一些非常好的(以及奇怪的!)原因这样做。

答案 3 :(得分:2)

假设您要将所有权shared_ptr转移到auto_ptr,这只有在

时才有可能
  • shared_ptr的引用计数为1,
  • shared_ptr最初是使用自定义删除功能创建的,
  • 你知道删除函数的类型。

鉴于此,方法如下:

#include <iostream>
#include <boost/shared_ptr.hpp>     // boost::shared_ptr
#include <memory>                   // std::auto_ptr

typedef boost::shared_ptr<int>  IntSharedPtr;
typedef std::auto_ptr<int>      IntAutoPtr;

template< class Type >
void myCustomDeleter( Type* p )
{
    delete p;
}

IntSharedPtr newSharedInt()
{
    return IntSharedPtr( new int( 42 ), &myCustomDeleter<int> );
}

IntAutoPtr makeAutoFrom( IntSharedPtr& sp )
{
    struct Dummy
    {
        static void deleter( int* ) {}
    };

    typedef void (*DeleterFunc)( int* );

    if( sp.use_count() > 1 ) { return IntAutoPtr( 0 ); }
    DeleterFunc*    d   = boost::get_deleter<DeleterFunc>( sp );

    if( d == 0 ) { return IntAutoPtr( 0 ); }

    int* const  p   = sp.get();
    *d = &Dummy::deleter;
    sp.reset();
    return IntAutoPtr( p );
}

template< class T >
T& refTo( T const& r ) { return const_cast< T& >( r ); }

int main()
{
    IntAutoPtr  p( makeAutoFrom( refTo( newSharedInt() ) ) );

    std::cout << (p.get() == 0? "Failed" : "Worked" ) << std::endl;
}

注意:此技术不是线程安全的。

干杯&amp;第h。,

答案 4 :(得分:1)

你不应该这样做,因为auto_ptr取得了指针的所有权。

但你可以这样做,但请确保在超出范围之前致电release

void foo(shared_ptr<Y> s)
{
    auto_ptr<Y> a(s.get());

    // use a

    a.release();
}

编辑:以上解决方案不是例外安全。以下内容应该有效,将 guard 类与无法复制const auto_ptr的保证相结合:

void bar(const auto_ptr<Y>& p);

struct as_const_auto_ptr
{
    explicit as_const_auto_ptr(const shared_ptr<Y>& p) : p(p), a(p.get()) {}
    ~as_const_auto_ptr() {a.release();}
    operator const auto_ptr<Y>&() {return a;}
    const shared_ptr<Y> p;
    auto_ptr<Y> a;
};

void foo(shared_ptr<Y> s)
{
    as_const_auto_ptr a(s);

    // use a.
    bar(a);
}