Smart Pointers - What, Why, Which? - Yonat Sharon
Smart pointers emulate raw pointers in C++, but handle memory management. This allows the programmer to use the pointer normally, but not worry about cleaning up behind it. The simplest example of smart pointers is auto_ptr which is simply a wrapper around a raw pointer, behaving identically as far as dereferencing and indirection is concerned, but the difference lies in the destructor which performs the delete on the contained raw pointer. As of the C++11 standard, std::auto_ptr has been deprecated in favor of std::unique_ptr. I will briefly discuss this later.
The article mentions many reasons for using smart pointers apart from the automatic cleanup mentioned above : smart pointers get initialized to NULL by default, the danger of dangling pointers is reduced since smart pointers allow you to explicitly test for NULL to ensure that the pointer is in fact pointing to something, enforcing strict ownership means that the same resource will not be deleted more than once, they allow for exception safety (see the RAII idiom) and preclude a situation which could cause a memory leak because an exception was thrown before delete could be called on the pointer. Smart pointers can also be used to increase efficiency by following the Copy on Write (COW) strategy - i.e. the same object is used by multiple pointers so long as they behave in a read-only fashion; the moment one of them attempts to modify the object, the smart pointer makes a copy. This kind of semantics is seen in the std::string class. Another reason for using smart pointers is their use in STL containers. Since STL containers store objects by value, it’s not possible to have Child objects being stored in a vector<Parent>. To overcome this, we could have a vector<Parent*>, however cleaning up afterwards is error-prone and not exception-safe. Using a smart pointer that cleans up after itself is obviously desirable. However, not all smart pointers can be used since STL containers may copy/ delete their elements while resizing, etc.Thus any smart pointer that transfers ownership (auto_ptr, may it rest in peace, did this) cannot be used.
So which smart pointers should one use, and when? The article keeps this section generalized, so I’ll try to review it in terms of the C++11 standard. If you have been using std::auto_ptr, then your best bet is to switch to std::unique_ptr keeping in mind that now ownership transfer is explicit using move and copy construction is prohibited. The following is taken from Danny Kalev’s C++ reference guide:
auto_ptr<int> ap1(new int);
auto_ptr<int> ap2 = ap1; // OK, albeit unsafe
unique_ptr<int> up1(new int);
unique_ptr<int> up2 = up1; // compilation error
unique_ptr<int> up1(new int);
unique_ptr<int> up2 = move(up1); // ok, explicit move
Thus unique_ptr should be used when we want a single pointer to an object whose memory will automatically get reclaimed when the single owning pointer gets destroyed.
On the other hand, shared_ptr allows multiple pointers to point to the same object and the object is reclaimed only when the last shared_ptr to it is destroyed (it keeps track of this using reference counting, so one must beware of cycles). The use of shared_ptr is recommended within STL containers. There are other smart pointers that ship with the Boost library, and the interested reader can find a brief summary of them here and an interesting discussion on them here. In conclusion, smart pointers can be quite helpful in preventing subtle memory management bugs, and with the introduction of some of the popular Boost smart pointers in the current C++ standard, there’s all the more reason to use them.
No comments:
Post a Comment