Reputation: 519
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 ?
Upvotes: 8
Views: 587
Reputation: 519
I've realized the answer to my own question:
In the code
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// HERE
}
the destructor of q is guaranteed to be called upon scope exit (HERE).
While the compiler is allowed to allocate and free registers for variables as it pleases, the destructor is guaranteed to be called in a particular place - scope exit.
How do I know ?
Because this is what enables C++ scope guard. Oftentimes the scope guard is used to release a mutex on scope exit - this is something that needs to be guaranteed.
Upvotes: 0
Reputation: 217810
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
...
}
Upvotes: 5