Smart Pointers : Implementation of unique_ptr & auto_ptr

Share the Article

auto_ptr

The auto_ptr is one of the simplest smart pointers. This pointer internally manages a resource and deletes it when pointer goes out of scope. The auto_ptr accepts a handle to raw resource while creation.

auto_ptr<int> ap1(new int(2));

This is defined in include file

#include <memory>

Copy Operation

The auto_ptr transfers the ownership of internal resource during a copy operation. Furthermore, such a behavior happens in both the cases of copy. That is whenever a new auto_ptr is constructed using copy constructor or whenever an assignment operation happens.

auto_ptr<int> ap2 = ap1; //ap2 created by copy construction ap3 = ap2; //Copy by assignment operator

Operations related to access of internal resource

The autoptr overloads two special member functions, dereference (“*”) and arrow (“->”) operators. This enables access to internal resource just like a regular pointer.

auto_ptr<std::string> ap4(new std::string("mainfunda")); cout << *ap4 << endl; // * returns reference to resource cout << ap4->size() << endl; // returns pointer to resource

Other operations related to ownership

The auto_ptr also implements members to relinquish the resource.

T* release(); //Returns raw handle, now points to NULL void reset( T* p = 0 ); //Replaces internal pointer with "p"

Problem with auto_ptr smart pointers

The auto_ptr is a deprecated feature in C++11. This is because, there are potential problems related to the way it manages ownership of the resource.


Firstly, during the copy operation, when auto_ptr invokes copy constructor, it silently removes the reference in RHS object. This means that the RHS object has now become invalid. Due to this, any attempt to use this object shall cause undefined behavior in program.

In the following example, the new auto_ptr a5 takes the ownership of resource from existing auto_ptr a4. Consequently, any attempt to access the resource in old object will cause crash.

auto_ptr<std::string> ap4(new std::string("mainfunda")); auto_ptr<std::string> ap5 = ap4; cout << *ap4 << endl; //This will crash cout << ap4->size() << endl; //This will crash

The second problem with copy is that to take the control, it modifies the RHS object. Therefore, any unintended copy operations may give rise to dangling pointers.

Typical implementation of auto_ptr

#include<iostream> //main header using namespace std;//namespace template<typename T> class the_auto_ptr { T* ap_data; public: the_auto_ptr(T* p) { ap_data = p; } the_auto_ptr(the_auto_ptr& ap_rhs) : ap_data(ap_rhs.release()) { ap_rhs.ap_data = NULL; } the_auto_ptr& operator=(const the_auto_ptr& ap_rhs) { ap_data = ap_rhs.release(); return (*this); } T& operator*() { return (*ap_data); } T* operator->() { return ap_data; } T* release() { T* rawPtr = ap_data; ap_data = NULL; return rawPtr; } ~the_auto_ptr() { cout << "Automatic clean-up" << endl; if(ap_data) delete ap_data; ap_data = NULL; } }; int main() { the_auto_ptr<int> ap1(new int(2)); the_auto_ptr<int> ap2 = ap1; *ap2 = 4; cout << *ap2 << endl; the_auto_ptr<std::string> ap4(new std::string("mainfunda")); the_auto_ptr<std::string> ap5 = ap4; cout << *ap5 << endl; cout << ap5->size() << endl; return 0; }

The output of the above program will be.

4 mainfunda 7 Automatic clean-up Automatic clean-up Automatic clean-up Automatic clean-up

unique_ptr

The unique_ptr is also a smart pointer but takes care of the excusive ownership of internal resource. In most of the use-case, its behavior is same as the auto_ptr. However, unique pointer ensures that any transfer of ownership happens by moving the pointer.

unique_ptr<int> uptr1 = new int(2); unique_ptr<int> uptr2 = std::move(uptr1); //Move the ownership

Any attempt to copy shall fail during compiler only. In following code, snippet, the ownership is not moved but copied.

std::unique_ptr<int> up1 = new int; std::unique_ptr<int> up2 = up1; //This is wrong

The compiler shall generate following error:

compiler error for using an existing unique_ptr to construct another smart pointer

Delete copy operations

The implementation specifically deletes both the copy constructor as well as assignment operator.

the_unique_ptr(const the_unique_ptr& up_rhs) = delete; the_unique_ptr& operator=(const the_unique_ptr& up_rhs) = delete;

Introduction of Move member functions

The unique_ptr internally uses move member functions (constructor and assignment). Since, these members accepts only an R-value parameter, therefore unique_ptr will not accept any L-value unique_ptr. The reason behind this design is that a user must do an explicit move and pass an R-value. Therefore, there shall be no chance of unintended copy. Finally, the move shall transfer ownership of resource by explicit move of internal resource.

the_unique_ptr(the_unique_ptr&& up_rhs) //move constructor { up_data = std::move(up_rhs.up_data); up_rhs.up_data = NULL; }

Typical implementation of unique_ptr

#include <iostream> //main header using namespace std; //namespace template<typename T> class the_unique_ptr //smart pointers implementation { T* up_data; public: the_unique_ptr(T* p) { up_data = p; } the_unique_ptr(const the_unique_ptr& up_rhs) = delete; the_unique_ptr(the_unique_ptr&& up_rhs) { up_data = std::move(up_rhs.up_data); up_rhs.up_data = NULL; } the_unique_ptr& operator= (const the_unique_ptr& up_rhs) = delete; the_unique_ptr& operator= (the_unique_ptr&& up_rhs) { up_data = std::move(up_rhs.up_data); up_rhs.up_data = NULL; return (*this); } T& operator*() { return (*up_data); } T* operator->() { return up_data; } ~the_unique_ptr() { cout << "Automatic clean-up" << endl; if(up_data) delete up_data; up_data = NULL; } }; int main() { the_unique_ptr<int> up1 = new int(2); the_unique_ptr<int> up2 = std::move(up1); *up2 = 4; cout << *up2 << endl; the_unique_ptr<std::string> up3 = new std::string("mainfunda"); the_unique_ptr<std::string> up4 = std::move(up3); cout << *up4 << endl; cout << up4->size() << endl; return 0; }

The above program shall generate following output.

4 testing 7 Automatic clean-up Automatic clean-up Automatic clean-up Automatic clean-up

Main Funda: unique_ptr manages exclusive ownership of internal resource

Related Topics:

 What are the drawbacks of using enum ?
Which member functions are generated by compiler in class?
How to stop compiler from generating special member functions?
Compiler Generated Destructor is always non-virtual
How to make a class object un-copyable?
Why virtual functions should not be called in constructor & destructor ?
Explaining C++ casts
How pointer to class members are different ?
How std::forward( ) works?
Rule of Three
How std::move() function works?
What is reference collapsing?
How delete keyword can be used to filter polymorphism
emplace_back vs push_back

Share the Article

Leave a Reply

Your email address will not be published. Required fields are marked *