std::unique_ptr in C++ is a smart pointer in that provides automatic memory management for dynamically allocated objects. It is part of the C++11 standard and helps manage the lifetime of dynamically allocated resources.
First let’s see the key properties and example of the Unique pointer in C++, that will give clear picture about it. The we will discuss on unique pointers and function.
Key properties of Unique_ptr:
- Uniqueness: A unique_ptr “owns” the object it points to, ensuring that only one unique_ptr can manage a particular object. This enforces a strict one-to-one ownership relationship.
- Copying and Ownership: unique_ptr cannot be directly copied, as it would violate the uniqueness principle. However, it can be moved, transferring ownership from one unique_ptr to another.
- Lifetime Management: The managed object is automatically deleted when the unique_ptr goes out of scope, ensuring that memory is properly deallocated.
- Use Cases: unique_ptr is ideal for cases where exclusive ownership is required, such as managing resources that must be released explicitly, like dynamically allocated memory or file handles.
unique_ptr Example:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main() {
std::unique_ptr<int> myPtr = std::make_unique<int>(35);
// myPtr owns the dynamically allocated int with value 35
std::unique_ptr<int> anotherPtr = std::move(myPtr);
// ownership transferred, myPtr is now null, anotherPtr owns the object
if (anotherPtr) {
// Check if anotherPtr is not null before using it
int value = *anotherPtr; // Access the value
// no need to delete, memory will be automatically freed
} // anotherPtr goes out of scope, the object is deleted
return 0;
}
Highlights:
- Advantages: Prevents memory leaks by automatically managing memory deallocation. Eliminates the need for manual delete, reducing the chance of errors. Helps enforce clear ownership semantics.
- When to Use: Use unique_ptr when you need a single owner for a dynamically allocated resource. Avoid using it in scenarios where shared ownership is required.
- When It Dies: The managed object is deleted automatically when the unique_ptr goes out of scope, ensuring timely resource release.
Passing unique_ptr in C++ to a function
Here’s 2 points to note:
- You cannot pass a unique pointer to a function by value, but you can pass it by reference.
- However, you can use move semantic to transfer ownership to the unique pointer declared in the function parameter, then it will work. Examples below will clarify you.
Passing by value:
You cannot pass the unique pointer ptr to the function f(std::unique_ptr<int> p) by value, because the unique pointer ptr in the main() holds the ownership of the int. when you pass it as f(ptr), it will look like std::unique_ptr<int> p = ptr, // COPY, so there is an ERROR on making copy because you cannot a copy of the unique pointer.
void f(std::unique_ptr<int> p) {
cout<<*p;
}
int main() {
auto ptr = std::make_unique<int>(100);
f(ptr);
return 0;
}
Passing by reference:
In the above code, If you pass the unique pointer by reference, then it’s ok. NOTICE the unique pointer declaration in the function f(std::unique_ptr<int>& p). The code will print the output 100 inside the function.
Using move semantic:
Here, the move function transferring the ownership to unique pointer “p”, declared in the function. So, this code will work fine.
void f(std::unique_ptr<int> p) {
cout<<*p;
}
int main() {
auto ptr = std::make_unique<int>(100);
// use move to transfer ownership of the object from
//ptr to the function pointer p.
f(move(ptr));
return 0;
}
Returning unique_ptr from a function:
You can return a unique pointer from a function. The below code works fine.
CATCH: We discussed that you cannot make a copy of an unique pointer. That’s right. But, here when you return the unique pointer and assign it to the q pointer in the main function, there should be an error, but it works. HOW? Answer is: copy elision. Returning a unique pointer allowed.
auto f(std::unique_ptr<int> p) {
*p = 50;
return p;
}
int main() {
auto ptr = std::make_unique<int>(100);
cout<< "Before function call..."<<*ptr <<endl;
std::unique_ptr<int> q = f(move(ptr));
cout<< "After function call..."<<*q;
return 0;
}