views:

68

answers:

3

Why can I not do this?

boost::shared_ptr<QueuList> next;

void QueuList::SetNextPtr(QueuList* Next)
{
    boost::mutex mtx;

    boost::mutex::scoped_lock lock(mtx);
    {// scope of lock
        //if (next == NULL)  // is this needed on a shared_ptr??
        next = Next;  // Why can I not assign a raw ptr to a shared_ptr????
    }

}

How should I do it instead??

EDIT: Calling this method when the next variable is assigned properly, it still causes an error when the QueuList object is destroyed for some reason. I get a debug assertion. The destructor of the object does nothing in particular. It only crashes when I call this function:

    QueuList li;
    QueuList lis;

    li.SetNextPtr(&lis);

When main goes out of scope, I get a debug assertion... Any ideas??

+4  A: 

This is done to prevent accidentally assigning pointers to a shared_ptr whose lifetime is managed independently. You have to explicitly create a shared_ptr that then takes ownership of the object.

next = boost::shared_ptr<QueueList>( Next );

Edit about your edit The problem is that in your case the shared_ptr takes ownership of an object on the stack. Then two things can happen:

  1. The stack-frame of the object gets cleared before the shared_ptr reaches a reference count of 0. In that case, the shared_ptr will try to delete a non-existing object somewhere later, leading to undefined behavior.
  2. The shared_ptr reaches a reference count of 0 before the stack-frame is cleared. In that case, it will try to delete an object on the stack. I do not know exactly what happens in that case, but I would assume that it is undefined behavior too.
Space_C0wb0y
Or just use the reset Member function - `next.reset(Next);`
pgroke
@sbi: Thanks, fixed.
Space_C0wb0y
+1  A: 

Putting a pointer inside a shared_ptr transfers ownership of the pointer to the shared_ptr, so the shared_ptr is responsible for deleting it. This is conceptually an important operation, so the designers of shared_ptr didn't want it to just happen as part of a normal-looking assignment. For example, they wanted to prevent code like:

some_shared_ptr = some_other_smart_pointer.get();

which looks fairly innocuous, but would mean that both smart pointers thought they had responsibility for cleaning up the pointer, and would likely double-delete the pointer or something similar.

This is what's happening with your debug assertion. Calling SetNextPtr(&lis) passes ownership of &lis to the shared_ptr, and "ownership" means that the shared_ptr will call delete on its pointee when the last copy of the shared_ptr goes out of scope. So you're effectively deleting a local (stack) variable - lis - which corrupts the stack and causes the crash.

Doug
so if lis is a pointer itself, passing it to this function will cause it to be owned by the shared_ptr or will I still need to delete my lis pointer?
Tony
Doug
I was talking about a pointer as this: QueuList* lis = new QueuList();
Tony
OK, yes, so if you pass the result of `new QueuList()` to that function, then you don't (and mustn't) delete it anywhere else.
Doug
+1  A: 

You can use the Reset() function rather than the wordier next = boost::shared_ptr<QueueList>(Next);

next.Reset(Next);
Mark Ingram