在以下示例中,当调用goto
“向后”时,将调用A
的析构函数。为什么会那样?对象a
不会离开它的范围,是吗?标准是否就goto
的这种行为说了什么?
void f()
{
start:
A a;
goto start;
}
答案 0 :(得分:24)
第2段:
退出范围(无论多么已完成)时,在该范围内构建的具有自动存储持续时间(3.7.3)的对象将按其构造的相反顺序销毁。 [注:对于临时学生,见12.2。 -end note]从一个循环中转出一个循环,或返回一个具有自动存储持续时间的初始化变量涉及具有自动存储持续时间的对象的销毁,这些对象在转移点的范围内。但没有转移到。 (转入块中见6.7)。 [注意:但是,程序可以终止(例如,通过调用std :: exit()或std :: abort()(18.5)),而不会破坏具有自动存储持续时间的类对象。 - 结束说明]
我认为重要的部分是:
或者回溯过具有自动存储持续时间的初始化变量涉及销毁
答案 1 :(得分:14)
对象a
的生命周期从其声明开始,并延伸到包含它的块的末尾。
这意味着,在跳转到声明之前,你跳转到堆栈框架本地不存在的情况,所以它必须被破坏
名称的
point of declaration
紧跟在其完整的声明者(第8条)之后和其初始化者之前(如果有的话),[...](第3.3.2节)
块(6.3)中声明的名称是该块的本地名称;它有块范围。它的潜在范围始于它 声明点(3.3.2)并在其块结束时结束。在块作用域中声明的变量是本地的 变量。 (第3.3.3节)
答案 2 :(得分:12)
以下是该标准的相关引用。它甚至包括一个几乎与你的相同的例子:
C ++ 11 6.7声明声明[stmt.dcl]
2 每次声明语句时,都会初始化具有自动存储持续时间(3.7.3)的变量 执行。块中声明的具有自动存储持续时间的变量在退出时被销毁 块(6.6)。
3可以转换为块,但不能以初始化方式绕过声明。一个 程序从具有自动存储持续时间的变量不在范围内的点跳转到a 除非变量具有标量类型,具有普通默认值的类类型,否则它在范围内的点是不正确的 构造函数和一个普通的析构函数,这些类型之一的cv限定版本,或其中一个的数组 在没有初始值设定项的情况下声明前面的类型(8.5)。 [例如:
void f() {
// ...
goto lx; // ill-formed: jump into scope of a
// ...
ly:
X a = 1;
// ...
lx:
goto ly; // OK, jump implies destructor
// call for a followed by construction
// again immediately following label ly
}
-end example]
如示例中所述,goto
意味着破坏。声明语句(代码中为A a;
)表示每次跳转后重构执行构造函数。
答案 3 :(得分:1)
简单地说...... start:
是一个标签,并声明[另一个]范围
假设start
为<0x00003000>
,A a将在<0x00003000> + some_offset
说<0x00003004>
。
goto start
会要求PC(程序计数器)转到A的声明之前发生的地址 - 在它的范围之外 - 因此“ destroy {{1 “调用析构函数。