可以优化智能指针吗?
Can a smart pointer be optimized away?
注意代码
...
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// make use of 'p'
}
...
在上面的代码中,唯一指针 q 仅用于在时机成熟时释放 p。 Q本身没有使用
由于 q 从不在其声明的行下方使用,它似乎可以在声明后立即释放,从而利用 p "use after free".
问题是 q 保证 继续存在直到超出当前范围,或者编译器的优化器可以在 ?[=11 之前自由释放它=]
使用 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
可能会在全局范围内更改,编译器通常没有足够的信息(尽管链接器有),因此请考虑它们具有(潜在)可观察的行为(与任何外部函数一样) .
c++14 允许一些 elisions/optimisation 的新表达式,所以
{
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
...
}
可以由
"replaced"
{
// 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
...
}
我已经找到了我自己问题的答案:
在代码中
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// HERE
}
q的析构函数保证在作用域退出时调用(此处) .
虽然允许编译器随心所欲地为变量分配和释放寄存器,但保证在特定位置调用析构函数 - 范围退出。
我怎么知道?
因为这就是启用 C++ scope guard 的原因。通常,作用域守卫用于在作用域退出时释放互斥量 - 这是需要保证的事情。
注意代码
...
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// make use of 'p'
}
...
在上面的代码中,唯一指针 q 仅用于在时机成熟时释放 p。 Q本身没有使用
由于 q 从不在其声明的行下方使用,它似乎可以在声明后立即释放,从而利用 p "use after free".
问题是 q 保证 继续存在直到超出当前范围,或者编译器的优化器可以在 ?[=11 之前自由释放它=]
使用 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
可能会在全局范围内更改,编译器通常没有足够的信息(尽管链接器有),因此请考虑它们具有(潜在)可观察的行为(与任何外部函数一样) .
c++14 允许一些 elisions/optimisation 的新表达式,所以
{
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
...
}
可以由
"replaced"{
// 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
...
}
我已经找到了我自己问题的答案:
在代码中
{
int* p = new int(0);
std::unique_ptr<int> q(p);
...
// HERE
}
q的析构函数保证在作用域退出时调用(此处) .
虽然允许编译器随心所欲地为变量分配和释放寄存器,但保证在特定位置调用析构函数 - 范围退出。
我怎么知道?
因为这就是启用 C++ scope guard 的原因。通常,作用域守卫用于在作用域退出时释放互斥量 - 这是需要保证的事情。