Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

convert shared_ptr to auto_ptr?

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?

like image 317
ks1322 Avatar asked Jan 23 '11 11:01

ks1322


People also ask

Can you convert shared_ptr to Unique_ptr?

In short, you can easily and efficiently convert a std::unique_ptr to std::shared_ptr but you cannot convert std::shared_ptr to std::unique_ptr .

Why was auto_ptr removed?

Since the assignment-semantics was most-disliked feature, they wanted that feature to go away, but since there is code written that uses that semantics, (which standards-committee can not change), they had to let go of auto_ptr, instead of modifying it.

What happens when shared_ptr goes out of scope?

All the instances point to the same object, and share access to one "control block" that increments and decrements the reference count whenever a new shared_ptr is added, goes out of scope, or is reset. When the reference count reaches zero, the control block deletes the memory resource and itself.

Can shared_ptr be copied?

The ownership of an object can only be shared with another shared_ptr by copy constructing or copy assigning its value to another shared_ptr . Constructing a new shared_ptr using the raw underlying pointer owned by another shared_ptr leads to undefined behavior.


2 Answers

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!
like image 180
Artyom Avatar answered Sep 29 '22 09:09

Artyom


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
}
like image 37
GManNickG Avatar answered Sep 29 '22 09:09

GManNickG