Wednesday, March 4, 2009

why use shared_from_this() ?

Why would you need to use shared_from_this on an object? As the name implies, if you want to pass a shared pointer to *this (pointer to current object), then you use shared_from_this.

What happens if you don't? Well, a scenario could happen where you wrap *this pointer in a smart pointer from a member function, expecting that to work just fine. But what happens when you do that is you create another shared_ptr to *this with reference count of 1. When this member function exits, the shared_ptr gets destroyed, and your *this pointer is deleted, causing the destructor of the object to be called.

An example will make this clearer:
#include <iostream>
#include <boost/shared_ptr.hpp>

class Bar;
void foo(const boost::shared_ptr<Bar>& ptr);

class Bar
{
public:
void process()
{
foo(boost::shared_ptr<Bar>(this));
}
void print() const {std::cout << "I am still alive!!" << std::endl; }

~Bar() { std::cout << "Uh oh... I am dead!!" << std::endl; }
};

void foo(const boost::shared_ptr<Bar>& ptr)
{
ptr->print();
}

int main()
{
boost::shared_ptr<Bar> sPtr(new Bar());
sPtr->process();
sPtr->print();
std::cout << "Just before leavnig main " << std::endl;
sPtr->print();
return 0;
}


When you run this code (fix any errors first), it'll crash. The reason being, when the function process exits, the temporary shared_ptr resets its refcount to 0, and the *this object gets deleted. Then when main tries to delete the object again upon exit, it crashes.

To fix this, we use shared_from_this(), which will simply make sure that we get a smart pointer *this instead of a raw pointer *this. Read more about it in the boost docs


#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

class Bar;
void foo(const boost::shared_ptr<Bar>& ptr);

class Bar : public boost::enable_shared_from_this<Bar>
{
public:
void process()
{
foo(shared_from_this());
}
void print() const {std::cout << "I am still alive!!" << std::endl; }

~Bar() { std::cout << "Uh oh... I am dead!!" << std::endl; }
};

void foo(const boost::shared_ptr<Bar>& ptr)
{
ptr->print();
}

int main()
{
boost::shared_ptr<Bar> sPtr(new Bar());
sPtr->process();
sPtr->print();
std::cout << "Just before leavnig main " << std::endl;
sPtr->print();
return 0;
}

2 comments:

Abdalaziz Alsaydi said...

Not much C++ programming I do; but I liked the pointer tidbit. I came to get code formatting link. Yellah Sher'ob, Salam.

YemeniProgrammer said...

Use this tool for formatting code:

http://formatmysourcecode.blogspot.com/

The other one I used truncated my code :(