我的问题是:我是否保证编译器在括号中的块完成后不会从堆栈中清除变量?
我有这个片段:
void someMethod() {
Bar* barPtr;
if (foo != null) {
Bar bar = { foo->a, foo->b }; // (a)
barPtr = &bar;
}
else {
barPtr = nullptr;
}
Bar bar2 = { 42, 4711 }; // (c)
doSomethingElse(&bar2);
doSomething(barPtr); // (b)
}
注意bar
仅在上部块(a)中有效,而barPtr
在整个方法中有效。在(b)bar
不再适用范围。
barPtr
是否可以保存?bar
以存储(c)中定义的其他局部变量?答案 0 :(得分:3)
你问:
是否可以保证在用括号括起来的块之后不会清理堆栈?
保证是另一种方式。可以保证在用括号括起来的块之后清理堆栈,以便自动变量被破坏。
Bar* barPtr;
if (foo != null) {
Bar bar = { foo->a, foo->b }; // (a)
barPtr = &bar;
// bar is destructed after the block ends.
}
在阻止结束时,barPtr
指向悬空记忆。
答案 1 :(得分:3)
内存可以重复使用,即使没有,也无法触摸。你的对象是DEAD,它的析构函数在其范围的末尾运行。
标准说(3.8)
在对象的生命周期开始之前但在对象占用的存储空间已经被分配之后,或者在对象的生命周期结束之后以及在重用或释放对象占用的存储之前,任何引用的指针可以使用对象所在或存在的存储位置,但只能以有限的方式使用。
...
如果出现以下情况,程序会有未定义的行为:
...
- 指针用于访问非静态数据成员或调用对象的非静态成员函数
您可以使用指针(地址),但不能安全取消引用。
答案 2 :(得分:0)
在生命周期结束后访问对象的是Undefined Behavior。
相反,请替换此原始代码:
void someMethod() {
Bar* barPtr;
if (foo != null) {
Bar bar = { foo->a, foo->b }; // (a)
barPtr = &bar;
}
else {
barPtr = nullptr;
}
Bar bar2 = { 42, 4711 }; // (c)
doSomethingElse(&bar2);
doSomething(barPtr); // (b)
}
......用这个:
void someMethod() {
auto const doThings = []( Bar* barPtr ) -> void
{
Bar bar2 = { 42, 4711 }; // (c)
doSomethingElse(&bar2);
doSomething(barPtr); // (b)
};
if (foo != null) {
Bar bar = { foo->a, foo->b }; // (a)
doThings( &bar );
}
else {
doThings( nullptr );
}
}
或者,您喜欢的任何其他重构。