C++ 当我们把RAII和GOTO结合起来时会发生什么?

C++ 当我们把RAII和GOTO结合起来时会发生什么?,c++,goto,raii,C++,Goto,Raii,我只是出于好奇(因为没有人应该写这样的代码!)想知道RAII的行为如何与goto的使用相结合(这不是个好主意) 在VisualStudio2005中运行以下代码时,我得到以下输出 1,2,3 BOO! 然而,我想象,猜测,希望‘嘘!’实际上不会出现幽灵,因为它不应该被实例化(IMHO,因为我不知道这段代码的实际预期行为) 怎么了 我刚刚意识到,如果我为Ghost实例化一个显式构造函数,代码就不会编译 class Ghost { public: Ghost() {

我只是出于好奇(因为没有人应该写这样的代码!)想知道RAII的行为如何与goto的使用相结合(这不是个好主意)

在VisualStudio2005中运行以下代码时,我得到以下输出

1,2,3 BOO!
然而,我想象,猜测,希望‘嘘!’实际上不会出现幽灵,因为它不应该被实例化(IMHO,因为我不知道这段代码的实际预期行为)

怎么了


我刚刚意识到,如果我为Ghost实例化一个显式构造函数,代码就不会编译

class Ghost
{
public:
    Ghost()
    {
        printf(" HAHAHA! ");
    }
    ~Ghost()
    {
        printf(" BOO! ");
    }
};

啊,神秘…

标准明确地谈到了这一点——举个例子;6.7/3“声明声明”(由我补充强调):

具有自动存储持续时间的变量在每次执行其声明语句时初始化块中声明了自动存储持续时间的变量在退出块时被销毁

可以传输到块中,但不能以通过初始化绕过声明的方式传输。从具有自动存储持续时间的局部变量不在作用域内的点跳到它在作用域内的点的程序是格式错误的,除非该变量具有POD类型并且在没有初始值设定项的情况下声明

[示例:

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
}
-[结束示例]

因此,在我看来,MSVC的行为不符合标准-
Ghost
不是POD类型,因此当
goto
语句被编码为跳过它时,编译器应该发出一个错误


我尝试过的其他几个编译器(GCC和Digital Mars)出现了错误。Comeau发出警告(但公平地说,我的Comeau构建脚本已配置为具有高MSVC兼容性,因此它可能有意追随微软的领导)。

Goto没有放射性。后藤离开和例外离开没有什么不同。通过后藤进入应该是出于方便,而不是语言的限制。不知道鬼魂是否被建造是一个很好的理由不这样做


在构造函数之前跳进去。如果您想在某个对象已经构造好之后跳入,请将其包含在一个新的作用域中,或者自己解决它的生存期问题。

在这个场景中,我发现以下方法很有用

void foo()
{
    {
        Two t;
        printf("1,");
        goto JUMP;
    }

    {
        Ghost g;
        // operations that use g.
    }

// g is out of scope, so following JUMP is allowed.
JUMP:
    printf("3");
}

在foo()函数中限制变量g的作用域将使goto跳转合法。现在,我们不是从一个g没有初始化的地方跳到一个g应该被初始化的地方。

我相信这个行为是正确的。否则,如何在跳转后引用变量g?感谢您找到了标准中定义的位置!然而,我想知道格式错误是否意味着它应该或不应该编译……“格式错误”意味着程序不是“格式正确”。编译器只需要接受和“正确执行”格式正确的程序。也就是说,如果它是“格式不正确”,那么它就是错误的。@Robert:我在这里补充了几句关于MSVC行为的话,就像我一开始应该做的那样。@greyfade:但是编译器通常会接受某些格式不正确的程序,除非您将它们放入某种“严格”模式。例如,程序
intmain(){1LL;}
的格式不正确,但可能需要一些努力才能说服编译器告诉您这一点。不过,在这种情况下,如果行为是(a)由MSVC定义的,则跳过初始化只能被描述为MSVC扩展;(b)可能有用。你的公平供词听起来像是科莫在做一些不符合标准的事情。但是,它会发出警告,因此它可以满足标准的所有要求。
void foo()
{
    {
        Two t;
        printf("1,");
        goto JUMP;
    }

    {
        Ghost g;
        // operations that use g.
    }

// g is out of scope, so following JUMP is allowed.
JUMP:
    printf("3");
}