C++编程法则365天一天一条(2)goto语句的一些坑

如果使用非本地跳转语句(如goto)从自动变量的作用域退出(即跨越了自动变量的声明所在位置),比如从某个语句块的内部向外跳出,或者从一个函数的任何位置返回时,那么程序会按照它们创建时相反的顺序调用所有已定义析构函数的自动变量进行销毁操作。

换句话说,C++编译器将按照变量定义的相反顺序调用自动变量的析构函数,以保证在变量结束其生命周期之前能够完成它们所需的清理工作(比如释放分配的内存等)。具体过程可以简单概括为:

  1. 当自动变量被声明时,它们被创建并初始化。
  2. 当自动变量的作用域结束时(例如,离开特定语句块,返回到函数外部),它们会被销毁,并按照它们创建的相反顺序调用析构函数。这意味着最后定义的变量会先被销毁。

如果使用了跳转语句(如goto)进入了自动变量的作用域,程序就会非法(无法通过编译),除非所涉及的变量都具有以下特点:

  1. 声明了而没有初始化的标量类型(如整型、浮点型等)。
  2. 声明了而没有初始化,并且具有平凡默认构造函数和析构函数的类类型。
  3. 类型为上述两种情况中一种或多种CV修饰版本(如const或volatile等)。
  4. 其中一个以上的上述情况形成的数组类型。

换句话说,如果要从一个变量声明(例如、int x;语句)之后跳转到该变量的作用域内,就必须确保变量满足上述任一特定情境,否则程序将被视为“无法编译”,并抛出编译错误信息。这个规定主要是为了防止程序中存在未初始化的变量,它们可能引发各种难以预料的问题和未定义行为。

需要注意的是,上述规定仅适用于自动变量,在栈中分配内存的对象,对于静态变量或全局变量来说则不适用。此外,即使条件允许自动变量跨越作用域,也应该谨慎使用非本地的控制转移语句,如gotolongjmp。遵循良好的编码实践和规范,可以减少由于程序错误和不当编码而导致的问题,提高代码的可维护性和健壮性。

例如:

    goto label;
    int x = 1;
label:
    std::cout << x;

这段代码编译出错。

猜你喜欢

转载自blog.csdn.net/HandsomeHong/article/details/130790900
今日推荐