std::unique_ptr
It is smart pointer, it is a part of C++11. It owns the object and in other word it implements the “exclusive ownership” (two pointer cannot point to same object). Technically std::unique_ptr is a class template and class template contains raw pointer and this raw pointer points to one object at a time but ownership can be transferred.
Problem with raw pointer:
- memory leak can happen (if forget to add “delete” or exception occurs before delete).
- dangling pointer can be created.
- multiple delete error can be happened.
key points of unique pointer:
- exclusive ownership.
- avoid memory leak.
- do proper clean up.
- can NOT do copy operation.
- can NOT do assignment operation.
- can do only move operations (transfer ownership).
- If we want to return the unique pointer from function then just return it (internally it will use move operation so no need to worry).
- No arithmetic operation permitted.
- unique pointer can be empty.
- simple interface and make less error prone.
Creation of an unique pointer:
{//type is int std::unique_ptr<int>up{new int{5}}; //type is std::string std::unique_ptr<std::string>up1{new std::string{"digestcpp"}}; //type is int[] std::unique_ptr<int[]>up2{new int[3]{1,2,3}}; //type is user defined data type (class), A is class std::unique_ptr<A> up3{new A}; //empty pointer std::unique_ptr<int> up4(); //old c++ initialization std::unique_ptr<int> up5(new int(5)); }//destructor will be called and heap memory will be released
Restriction inside unique pointer (below operations are not permitted):
- copy operation is prohibited (copy constructor is declared as “deleted function”)
- Assignment operator is prohibited (copy constructor is declared as “deleted function”)
std::unique_ptr<int> up{new int{5}}; std::unique_ptr<int> up4{up};//if we try copy operation then compiler will give below error std::unique_ptr<int> up5{}; up5=up; //if we Assignment operator then compiler will give below error error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&)
Access the object in unique pointer (please check below example):
- deference by operator* (if unique pointer manages single object then we can access the object using operator*)
- deference by operator-> (if unique pointer manages single object then we can access the object’s member function using operator->)
- deference by get() member function (if unique pointer manages single object then we can access the object’s pointer using get())
- deference by operator[] (if unique pointer manages array of objects then we can access individual object using operator[])
std::unique_ptr<int> up{new int{5}}; std::cout<<"Int Value:"<<*up<<std::endl; std::unique_ptr<std::string> up1{new std::string{"digestcpp"}}; std::cout<<"Unique pointer has -> operation:"<<up1->append(".com")<<std::endl; std::unique_ptr<int[]> up2{new int[3]{1,2,3}}; std::cout<<"Int[0] Value:"<<up2[0]<<std::endl; int* pIptr= up.get();//return pointer pointing to actual object std::cout<<"Int value using get():"<<*pIptr<<std::endl;
Other functionality (like reset, release, please check below example):
- reset() (delete the memory or resource and assign the nullptr)
- release() (give up the ownership, without calling delete, now delete responsibility is NOT with unique_ptr)
- get() (return the address of object, still delete responsibility with unique pointer, we can read the value.)
Header file:
#include<memory> under namespace std as std::unique_ptr
Source code with example:
/* Program:Unique Pointer Author: Alpha Master Date: 26 September 2021 */ //Header File #include<iostream> #include<memory> class A { }; int main() { std::cout<<"Unique Pointer"<<std::endl; //Unique pointer has int std::unique_ptr<int> up{new int{5}}; std::cout<<"Int Value:"<<*up<<std::endl; //Unique pointer has string std::unique_ptr<std::string> up1{new std::string{"digestcpp"}}; std::cout<<"String Value:"<<*up1<<std::endl; std::cout<<"Unique pointer has -> operation:"<<up1->append(".com")<<std::endl; //Unique pointer has int[] std::unique_ptr<int[]> up2{new int[3]{1,2,3}}; std::cout<<"Int[0] Value:"<<up2[0]<<std::endl; //Unique pointer has user defined data type std::unique_ptr<A> up3{new A}; //std::cout<<"Int Value:"<<*up<<std::endl; //Using get() member function int* pIptr= up.get(); std::cout<<"Int value using get():"<<*pIptr<<std::endl; if(up) std::cout<<"object is present"<<std::endl; else std::cout<<"No object"<<std::endl; //other functionality //release int* pInRe = up.release(); if(up) std::cout<<"object is present"<<std::endl; else std::cout<<"No object"<<std::endl; //reset //delete the object and reset to nullptr up.reset(); if(up) std::cout<<"object is present"<<std::endl; else std::cout<<"No object"<<std::endl; return 0; }
Output:
Unique Pointer Int Value:5 String Value:digestcpp Unique pointer has -> operation:digestcpp.com Int[0] Value:1 Int value using get():5 object is present No object No object
unique pointer with function:
We want to pass the unique pointer to function that we have 2 option:
- Pass by reference (actual object will be accessible in function)
- Pass by actual object (Need to do std::move() while calling)
If we want to return the unique pointer from function then just return it (internally it will use move operation so no need to worry)
/* Program:Unique Pointer with function Author: Alpha Master Date: 4 April 2021 */ //Header File #include<iostream> #include<memory> std::unique_ptr<int> fun1(int tmp) { std::unique_ptr<int>up{new int(tmp)}; std::cout<<"Value in fun1:"<<*up<<std::endl; return up; } void fun2(std::unique_ptr<int>& tmp) { std::cout<<"Value in fun2:"<<*tmp<<std::endl; return; } std::unique_ptr<int> fun3(std::unique_ptr<int> tmp) { std::cout<<"Value in fun3:"<<*tmp<<std::endl; return tmp; } int main() { std::cout<<"Unique Pointer with function"<<std::endl; std::unique_ptr<int>A = fun1(5); std::cout<<"Value first time:"<<*A<<std::endl; fun2(A); std::cout<<"Value second time:"<<*A<<std::endl; std::unique_ptr<int>B = fun3(std::move(A)); std::cout<<"Value third time:"<<*B<<std::endl; return 0; }
Output:
Unique Pointer with function Value in fun1:5 Value first time:5 Value in fun2:5 Value second time:5 Value in fun3:5 Value third time:5
/* Program: Unique pointer pass to function Author: Alpha Master Date: 23 September 2021 */ //Header File #include<iostream> #include<memory> #include<string> std::unique_ptr<std::string> addSuffix(std::unique_ptr<std::string> upt) { std::string temp = (*upt.get()) + " master"; std::cout<<temp<<std::endl; //reset upt.reset(new std::string(temp)); return upt; } int main() { std::cout<<"Unique pointer"<<std::endl; //Creat new object std::unique_ptr<std::string> up { new std::string {"alpha"}}; //pass this unique object to function std::unique_ptr<std::string> out = addSuffix(std::move(up)); std::cout<<"Output:"<<*out.get(); std::cout<<std::endl; return 0; }
Unique pointer alpha master Output:alpha master
unique pointer with class:
/* Program:Unique Pointer with external class Author: Alpha Master Date: 4 April 2021 */ //Header File #include<iostream> #include<memory> class A { std::unique_ptr<int>m_upI; std::unique_ptr<std::string>m_upS; public: A(int i, std::string s) { std::cout<<"In A Constructor"<<std::endl; m_upI.reset(new int(i)); m_upS.reset(new std::string(s)); } ~A() { std::cout<<"In B Destructor"<<std::endl; m_upI.reset(nullptr); m_upS.reset(nullptr); } int getInt() { return (*m_upI); } std::string getString() { return (*m_upS);} }; int main() { std::cout<<"Unique Pointer with Class"<<std::endl; { A obj(5, "digestcpp.com"); std::cout<<"Int:"<<obj.getInt()<<std::endl; std::cout<<"String:"<<obj.getString()<<std::endl; } std::cout<<"Outside Block"<<std::endl; return 0; }