Best Practices
A simple guideline that nearly eliminates the possibility of memory leaks is: always use a named smart pointer variable to hold the result of new. Every occurence of the new keyword in the code should have the form:
shared_ptr<T> p(new Y);
It is, of course, acceptable to use another smart pointer in place of shared_ptr above; having T and Y be the same type, or passing arguments to Y's constructor is also OK.
If you observe this guideline, it naturally follows that you will have no explicit delete statements; try/catch constructs will be rare.
Avoid using unnamed shared_ptr temporaries to save typing; to see why this is dangerous, consider this example:
void f(shared_ptr<int>, int);
int g();
void ok()
{
shared_ptr<int> p( new int(2) );
f( p, g() );
}
void bad()
{
f( shared_ptr<int>( new int(2) ), g() );
}
The function ok follows the guideline to the letter, whereas bad constructs the temporary shared_ptr in place, admitting the possibility of a memory leak. Since function arguments are evaluated in unspecified order, it is possible for new int(2) to be evaluated first, g() second, and we may never get to the shared_ptrconstructor if g throws an exception. See Herb Sutter's treatment (also here) of the issue for more information.
The exception safety problem described above may also be eliminated by using the make_shared or allocate_shared factory functions defined in boost/make_shared.hpp. These factory functions also provide an efficiency benefit by consolidating allocations.