Objects life-cycle is crucial. A mistake in determining an object’s lifecycle can lead to resource (e.g., memory, fd) leaks as the resource owned cannot be properly released and recycled for use. When the leak accumulates to a certain level, it crashes the whole system.Objects life-cycle is also complicated since the ownership of one object might be relinquished by, transferred to, or shared with different entities which include but are not limited to variables, arguments, modules, data structures, containers, and threads. Again, the resource has to be released and recycled by one of the owners at some undetermined point.There is no de-facto standard to determine objects life-cycle. Utilities like (garbage collection) that is used in Java, used in Objective-C and all those pointers (ptrs) in C++, all have their pros and cons. However, this article is not about pros and cons but is focused on C++ resource management helper classes, Smart Pointer, , and . future function GC ARC shared_ptr auto_ptr unique_ptr Smart pointer A is a wrapper class of a normal pointer. defines life-cycle with a reference count that reflects how many time the smart pointer object is referenced. smart pointer Smart point Next, I will show a simple implementation of a . The code is for demonstration purposes only, thus, there is no sanity check, no exception handling and no thread-safety guarantee. smart pointer #include <stdio.h> template < typename T > class SmartPointer {private:T* _pRes;int* _refCount; void _release() {if(--(*_refCount) == 0) {printf("---Valar Morghulis:%d\n",*_refCount);delete _pRes;delete _refCount;} else {printf("---not today:%d\n",*_refCount);}} public:SmartPointer() : _pRes(NULL), _refCount(NULL) {_refCount = new int(0);printf("SP default cons:%d\n",*_refCount);} SmartPointer(T* pRes) : _pRes(pRes), _refCount(NULL) {_refCount = new int(1);printf("SP cons:%d\n",*_refCount);} SmartPointer(const SmartPointer<T>& sp) : _pRes(sp._pRes), _refCount(sp._refCount) {(*_refCount)++;printf("SP copy cons:%d\n",*_refCount);} SmartPointer<T>& operator = (const SmartPointer<T>& sp) {this->_release(); // release the last resource it points to_pRes = sp._pRes;_refCount = sp._refCount;(*_refCount)++;printf("SP assign:%d\n",*_refCount);return *this;} ~SmartPointer() {this->_release();} // to mimic a real pointerT& operator* () {return *_pRes;} // to mimic a real pointerT* operator-> () {return _pRes;}}; class AClass {public:AClass() { printf("aclass cons\n"); }~AClass() { printf("aclass des\n"); }}; void l2(SmartPointer<AClass>& p) {SmartPointer<AClass> use3 = p; // >> SP copy cons:3} // >> ---not today:2 void l1(SmartPointer<AClass>& p) {SmartPointer<AClass> use2 = p; // >> SP copy cons:2l2(p);} // >> ---not today:1 int main() {AClass *res = new AClass(); // >> aclass consSmartPointer<AClass> aSmartP(res); // >> SP cons:1l1(aSmartP);} // >> ---Valar Morghulis:0// >> aclass des Result: aclass consSP cons:1SP copy cons:2SP copy cons:3---not today:2---not today:1---Valar Morghulis:0aclass des To briefly explain the code above: ‘s life-cycle is no more than that of an ordinary class. Thus, logic flow going out of a (function) scope destructs it; SmartPointer has two properties, and , both are allocated from heap. Thus, logic flow going out of a (function) scope DOES NOT destruct them; SmartPointer _pRes _refCount each time a is constructed with a valid (of type ), the plus ; SmartPointer _pRes T _refCount 1 each time a is destructed, in our case, by a logic flow going out of a scope, the minus ; SmartPointer _refCount 1 however, the destruction of does not necessarily lead to a destruction of : SmartPointer _pRes a) when is still larger than , simply reduce the and print _refCount 0 SmartPointer _refCount not today b) only when is set to by the minus, destructs the resource referred by and and print _refCount 0 SmartPointer _pRes All men must die So s work as handles that are used by different parts of a program to keep track and to control the resource instance. When all handles are destroyed, the resource is considered “not used”, and is deleted as well. In the end of this article, I will show some real handles that embody in real world. smart pointer smart pointer The sample showcases the usage of in program that is linear, which is rarely the case in real scenario. Rather, as mentioned before, the resource (i.e., the instance of ) can be shared, by multiple data structure and variables in parallel. smart pointer AClass shared_ptr (C++11) is the ’s implementation of the that is more robust than the demo code listed above. And it does not generate dodgy log. shared_ptr std smart pointer Automatic pointer An , though looks similar to , is totally different. It is a convenient helper class that destructs the resource whenever the logic flow going out of the scope, just in case a programmer forgets. To some extent, it makes a pointer (that refers to a memory chunk dynamically allocated in runtime) works similar to a stack variable (statically allocated in compiling time). automatic pointer smart pointer Example, AutoPointer v1.0: #include <stdio.h> template < typename T > class AutoPointer {private:T* _pRes; public:AutoPointer() : _pRes(NULL) {} AutoPointer(T* pRes) : _pRes(pRes) {} AutoPointer(const AutoPointer<T>& ap) : _pRes(ap._pRes) {} AutoPointer<T>& operator = (const AutoPointer<T>& ap) {delete _pRes;_pRes = ap._pRes; return \*this; } ~AutoPointer() {delete _pRes;} // to mimic a real pointerT& operator* () {return *_pRes;}// to mimic a real pointerT* operator-> () {return _pRes;}}; class AClass {public:AClass() {printf(“cons\n”);}~AClass() {printf(“des\n”);}int i;}; void l1(AutoPointer<AClass>& p) {AutoPointer<AClass> use2 = p;}//the resource has already been deallocated here int main() {AClass *res = new AClass();res->i = 5;AutoPointer<AClass> use1(res);l1(use1);}// abort, repeat deallocating pointer Result: consdesdesautop(1148,0x7fff74eff000) malloc: *** error for object 0x7f9940c03240: pointer being freed was not allocated*** set a breakpoint in malloc_error_break to debug[1] 1148 abort ./a.out As given by the code snippet above, works internally like a simplified that deallocates the resource regardless of the reference count (in fact, there is no reference count at all). automatic pointer smart pointer The shows a major drawback of the : the ownership can not be transferred (to ). As a result, even though the resource has been deallocate in , still consider itself as the owner of the and deallocates the pointer one time more. coredump automatic pointer l1() l1() main() automatic pointer How about implementing the copy constructor as well as the assignment operator so the ownership can be properly transferred? Example, AutoPointer v2.0: ......AutoPointer(AutoPointer<T>& ap) : _pRes(ap._pRes) {ap._pRes = NULL;} AutoPointer<T>& operator = (AutoPointer<T>& ap) {delete _pRes;_pRes = ap._pRes; ap.\_pRes = NULL; return \*this; }...... Result: consdes All seems good. Yet it is another example of “fixing one bug leads to another”. The new problem is that the two semantics, ownership-transferring and copy, are coupled. So it is not compatible to some of the library functions such as that takes one extra copy (as pivot in quick sort) as it destroys the previous one that is still in use. The detailed explanation of the problem can be found , and thanks for pointing out the mistake in the original implementation. std::sort here patatahooligan is the implementation of the . As discussed above, it is either not very interesting or problematic, so it is now deprecated. And we should use instead. std::auto_ptr std automatic pointer std::unique_ptr std::unique_ptr (C++11) is the ’s replacement of in C++11. With the newly added , the ownership of a can be safely transferred to another entity. Moreover, the copy semantic is disabled for s to avoid ambiguity we saw in AutoPointer v2.0. Like , the last owner of the pointer is responsible for deallocation. std::unique_ptr std std::auto_ptr rvalue and move semantics unique_ptr unique_ptr automatic pointer #include <iostream>#include <vector>#include <memory>#include <cstdio>#include <fstream>#include <cassert> class AClass {public:AClass() {printf(“cons\n”);}~AClass() {printf(“des\n”);}int i;}; std::vector< std::unique_ptr<AClass> > v; void l1() {std::unique_ptr<AClass> p1(new AClass()); // >> consp1->i = 1;v.push_back(std::move(p1));std::unique_ptr<AClass> p2(new AClass()); // >> consp2->i = 2;v.push_back(std::move(p2));} // p1 and p2 are not destructed here int main() {l1();for(auto& p: v) printf(“%d\n”, p->i);} // >> des// >> des Result: conscons12desdes As shown in the code snippet above, the is preserved across different owners. When the ownership has been to , does not deallocates the resource anymore. This gains a much wider usage. unique pointer moved vector v l1() unique pointer N.b., I would rather believe is the major reason of the introduction of the new compared to the improvement gained here, the is less significant. unique pointer move semantic. Because optimization enabled by and move rvalue Take home “I can understand the stuffs, but I’m not sure if I still remember them exactly next morning.” Sure. I will find some real world counterparts to enhance your memory. a is like a handle of a video game console. std::shared_ptr The console (resource) is “ by multiple players with handles, and the game should continue even if there is only one player left. Thus, “Game over” only when all players stop playing. shared” a is like a portable game console. std::unique_ptr One player at a time, and one should “ it to let another to play. “Game over” when the LAST player stops playing. move” a is a std::auto_ptr as it can not be easily d. move If you like this read please clap for it or follow by clicking the buttons. Thanks, and hope to see you the next time. Originally published at holmeshe.me .