Mind the code
...
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// make use of 'p'
}
...
In the code above, the unique pointer q is used solely to free p, when time comes. Q is not used by itself.
Since q is never used below the line where it is declared, it can seemingly be released immediately after being declared, thus making use of p "use after free".
The question is q guaranteed to live on until going out of the current scope, or the compiler's optimizer is free to free it before ?
Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too.
One of the advantages of smart pointers is, that they ensure due to RAII, that the actual object is deleted. When using a raw pointer, you need to have a delete for every possible exit point, and still an exception will lead to a memory leak. Smart pointers will also free the memory if an exception occurs.
Smart pointers perform automatic memory management by tracking references to the underlying object and then automatically deleting that object when the last smart pointer that refers to that object goes away.
Smart pointers are used to make sure that an object is deleted if it is no longer used (referenced). The unique_ptr<> template holds a pointer to an object and deletes this object when the unique_ptr<> object is deleted.
With the as-if rule, compiler is allowed to do any optimization as long as observable behavior is identical.
Freeing immediately q
/p
would not be allowed, as then you will use dangling pointer.
Though it can call destructor before end of scope:
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// make use of 'p'
...
// No longer use of p (and q)
...
// Ok, can delete p/q now (as long there are no observable behaviors changes)
...
}
As operator new
/delete
might be changed globally, compiler would generally not have enough information (linker has though), so consider they have (potentially) observable behaviors (as any external functions).
c++14 allows some elisions/optimisation of new expression, so
{
delete new int(42);
int* p1 = new int(0);
int* p2 = new int(0);
std::unique_ptr<int> q2(p2);
std::unique_ptr<int> q1(p1);
...
// make use of 'p1'/p2
...
}
Can be "replaced" by
{
// delete new int(42); // optimized out
std::unique_ptr<int[]> qs{new int [] {0, 0}}; // only one allocation instead of 2
int* p1 = q->get();
int* p2 = q->get() + 1;
...
// make use of 'p1'/p2
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With