Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a smart pointer be optimized away?

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 ?

like image 366
segfault Avatar asked Apr 14 '20 12:04

segfault


People also ask

What problem does using smart pointers help prevent?

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.

What is an advantage of using a smart pointer over a raw pointer?

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.

Do smart pointers automatically delete?

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.

What is the point of smart pointers?

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.


1 Answers

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
    ...
}
like image 140
Jarod42 Avatar answered Oct 13 '22 04:10

Jarod42