The performance overhead of using std::unique_ptr
compared to raw pointers in C++ is generally minimal, but it's worth understanding the differences.
In terms of memory usage, a std::unique_ptr
typically has the same size as a raw pointer on most implementations when using the default deleter. Let's check this:
#include <iostream>
#include <memory>
int main() {
std::cout << "Size of raw pointer: " << sizeof(int*)
<< " bytes\n";
std::cout << "Size of unique_ptr: "
<< sizeof(std::unique_ptr<int>) << " bytes\n";
}
Size of raw pointer: 8 bytes
Size of unique_ptr: 8 bytes
However, if you use a custom deleter, the size may increase:
#include <iostream>
#include <memory>
int main() {
auto customDeleter = [](int* p) { delete p; };
std::cout
<< "Size of unique_ptr with custom deleter: "
<< sizeof(
std::unique_ptr<int, decltype(customDeleter)>
) << " bytes";
}
Size of unique_ptr with custom deleter: 16 bytes
In terms of runtime performance:
std::unique_ptr
is typically as fast as dereferencing a raw pointer. Modern compilers can often optimize away any overhead.std::unique_ptr
using std::make_unique()
is generally as fast as using new
. Destruction is also typically as fast as using delete
.std::unique_ptr
is very fast, usually just involving pointer assignment.Here's a simple benchmark to illustrate:
#include <chrono>
#include <iostream>
#include <memory>
const int ITERATIONS = 10000000;
void benchmarkRawPointer() {
using namespace std::chrono;
auto start = high_resolution_clock::now();
for (int i = 0; i < ITERATIONS; ++i) {
int* p = new int(i);
*p += 1;
delete p;
}
auto end = high_resolution_clock::now();
duration<double> diff = end - start;
std::cout << "Raw pointer time: " << diff.count()
<< " s\n";
}
void benchmarkUniquePtr() {
using namespace std::chrono;
auto start = high_resolution_clock::now();
for (int i = 0; i < ITERATIONS; ++i) {
auto p = std::make_unique<int>(i);
*p += 1;
}
auto end = high_resolution_clock::now();
duration<double> diff = end - start;
std::cout << "Unique pointer time: " << diff.count()
<< " s\n";
}
int main() {
benchmarkRawPointer();
benchmarkUniquePtr();
}
Raw pointer time: 1.94922 s
Unique pointer time: 2.23576 s
The results will vary depending on your system, but they're often very close.
In practice, the small performance overhead of std::unique_ptr
is usually outweighed by the benefits of automatic resource management and exception safety. std::unique_ptr
helps prevent resource leaks and makes your code safer and easier to reason about, which can lead to better overall performance in complex systems.
Remember, premature optimization is the root of all evil. Always measure before optimizing, and consider the trade-offs between slight performance gains and code safety/maintainability.
Answers to questions are automatically generated and may not have been reviewed.
Learn how to manage dynamic memory using unique pointers and the concept of memory ownership