记住代码
...
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// make use of 'p'
}
...
在上面的代码中,唯一的指针 q 仅在时间到时用于释放 p 。 Q 本身不使用。
由于 q 从未在声明所在行下使用,因此它似乎可以在声明后立即释放,因此可以使用 p “先使用后释放”。 />
问题是 q 保证一直存在直到退出当前范围,否则编译器的优化程序可以在它之前自由释放它?
答案 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的原因。通常情况下,范围保护器用于在范围退出时释放互斥体-这是需要保证的。