A common scenario in C++ is to create a container of user defined objects.
#include <vector> class Option { public: .. } void vec_option(std::vector<Option*>& vec) { vec.push_back(new Option()); // .. Some additional code .. delete vec.back(); // Skipping this line causes a memory leak vec.pop_back(); // Causes a dangling pointer if this line isn't reached }
NOTE: If the code prior to delete vec.back; causes an exception to be thrown or returns from the function, this will lead to a memory leak or a dangling pointer.
Although the above code will compile and run, it is bad practice to use such containers of “dumb” pointers due to the fragility of the function.
One such smart pointer is std::auto_ptr<>.
Let's modify the function prototype code above to make use of it:
#include <vector> #include <memory> // Needed for std::auto_ptr<> class Option { public: .. } void vec_option(std::vector<std::auto_ptr<Option> >& vec) { vec.push_back(new Option()); .. vec.pop_back(); }
NOTE: When we try to compile this code we receive a compiler error! What just happened?
std::auto_ptr<> does not fulfill the requirements of being copy-constructible and assignable.
Since objects within an STL container must be copy-constructible and assignable, a compile time error is provided if an auto_ptr is used within a container.
Prior to the C++11 standard the best way to overcome this problem was to use the Boost library smart pointers.
#include <vector> #include <boost/shared_ptr.hpp> // Need to include the Boost header for shared_ptr class Option { public: .. } typedef boost::shared_ptr<Option> option_ptr; // This typedef stops excessive C++ syntax later void vec_option(std::vector<option_ptr>& vec) { option_ptr ptr_opt(new Option()); // Separate allocation to avoid problems if exceptions are thrown vec.push_back(ptr_opt); .. vec.pop_back(); }
NOTE: So why does this work?
In modern C++, which utilises the C++11 standard, the use of auto_ptrs has become deprecated.
#include <vector> #include <memory> // std::shared_ptr is included in the "memory" header class Option { public: .. } typedef std::shared_ptr<Option> option_ptr; // This typedef stops excessive C++ syntax later void vec_option(std::vector<option_ptr>& vec) { option_ptr ptr_opt(new Option()); // Separate allocation to avoid problems if exceptions are thrown vec.push_back(ptr_opt); .. vec.pop_back(); }
NOTE: Using shared pointers can be considered bad practice, as it means that the programmer has not given sufficient thought to the lifetime of the object or where it should actually be deleted.