是否可以优化智能指针?

时间:2020-04-14 12:11:13

标签: c++ c++11 smart-pointers

记住代码

...
{
    int* p = new int(0);
    std::unique_ptr<int> q(p);
    ...
    // make use of 'p'
}
...

在上面的代码中,唯一的指针 q 仅在时间到时用于释放 p Q 本身不使用。
由于 q 从未在声明所在行下使用,因此它似乎可以在声明后立即释放,因此可以使用 p “先使用后释放”。 /> 问题是 q 保证一直存在直到退出当前范围,否则编译器的优化程序可以在它之前自由释放它?

2 个答案:

答案 0 :(得分:5)

使用as-if规则,只要可观察到的行为相同,就允许编译器进行任何优化。

不允许立即释放q / p,因为那样您将使用悬挂指针。

尽管它可以在作用域结束之前调用析构函数:

{
    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)
    ...
}

由于operator new / delete可能会全局更改,因此编译器通常将没有足够的信息(尽管链接器具有),因此请考虑它们具有(潜在)可观察到的行为(与任何外部函数一样)。 / p>

c ++ 14允许对新表达式进行一些省略/优化,所以

{
    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
    ...
}

可以被“替换”

{
    // 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
    ...
}

答案 1 :(得分:0)

我已经意识到自己的问题的答案:
在代码

{
    int* p = new int(0);
    std::unique_ptr<int> q(p);
    ...
    // HERE
}

q 的析构函数保证在范围退出( HERE )时被调用。
尽管允许编译器根据需要分配和释放变量的寄存器,但可以确保在特定位置(作用域出口)调用析构函数。
我怎么知道?
因为这就是启用C ++ scope guard的原因。通常情况下,范围保护器用于在范围退出时释放互斥体-这是需要保证的。