将shared_ptr转换为auto_ptr?

发布于 2024-10-13 07:42:01 字数 222 浏览 18 评论 0原文

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

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

我可以将共享指针转换为自动指针吗?还是设计上不可能?

I need to obtain auto_ptr from shared_ptr in my code. I can do reverse operation - convert auto_ptr to shared_ptr as shared_ptr has such constructor:

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

Can I convert shared_ptr to auto_ptr? Or it is impossible by design?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

-黛色若梦 2024-10-20 07:42:01

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

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

编辑:

即使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!

It is impossible by design as the object may be shared with other shared pointer and thus "fetching" it to auto_ptr may lead to deleting referenced object.

For same reason shared_ptr has no "release" member function as auto_ptr.

Edit:

Even if shared_ptr had some kind of "release" method or allowed to remove its reference
without destroying the object it would not work for following case (threads 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!
[浮城] 2024-10-20 07:42:01

共享指针可以被很多东西共享,你不能以某种方式从它们那里获取它。这是由 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
}

A shared pointer can be shared by many things, you can't just take it from them all somehow. This is elaborated by Artyom and peoro.

One approach is to make a temporary auto_ptr, and release it from handling the pointer at the end of the scope. dalle outlines a first approach, but this suffers from lack of exception-safety (might accidentally delete), and it cannot protect you from accidentally passing it to a function that's going to transfer ownership (where the delete falls out of our hands).

We can make our own wrapper to avoid this, though:

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;
};

Now you can treat a shared_ptr like a const auto_ptr, in a scope:

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

    // use a
}
薄荷港 2024-10-20 07:42:01

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

让两个不同的对象持有同一指针的所有权可能会导致运行时错误,除非您出于某些非常好的(并且奇怪!)原因这样做。

Usually it's a bad idea, since both auto_ptr and shared_ptr take the ownership of your pointer (they'll care about destroying it and stuff, according to different policies).

Having two different objects holding the ownership for the same pointer will likely result in run time errors unless your doing it for some really good (and weird!) reasons.

与他有关 2024-10-20 07:42:01

假设您想要将所有权从 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;
}

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

干杯&呵呵,

Assuming you want to transfer ownership from a shared_ptr to auto_ptr, this is only possible when

  • The reference count of the shared_ptr is 1, and
  • the shared_ptr was originally created with a custom deleter function, and
  • you know the type of that deleter function.

Given that, here's how:

#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;
}

Note: this technique isn't thread-safe.

Cheers & hth.,

ぃ双果 2024-10-20 07:42:01

您不应该这样做,因为 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);
}

You should not do that, as auto_ptr takes ownership of the pointer.

But you can do it, but make sure you call release before you fall out of scope.

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

    // use a

    a.release();
}

EDIT: The above solution is not exception safe. The following should work, combining a guard class with the guarantee that a const auto_ptr cannot be copied:

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文