gpt4 book ai didi

c++ - C/C++ 中可中断的命名范围

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:40:54 25 4
gpt4 key购买 nike

介绍

这个问题来自这个问题:The named loop idiom : dangerous? .对于不想阅读原始问题的人来说,这是关于做这样的事情:

named(label1) for(int i = 0 ; i < 10 ; i++) {
for(int j = 0 ; j < 10 ; j++) {
if(some_condition)
break(label1); // exit outer loop
}
}

这个新问题是关于“命名循环”习语的改进版本。如果你懒得阅读整篇文章,你可以直接进入这篇文章的“示例”部分,清楚地理解我在说什么。

设计缺陷

不幸的是,这个问题很快就结束了(后来又重新打开了),因为它更像是一个利弊辩论,而不是一个纯粹的技术问题。似乎它不适合 SO Q&A 格式。此外,我提供的代码有几个缺陷:
  • 关键词break由宏重新定义
  • 宏是用小写字母写的
  • 它使一些可怕的东西可以编译(至少使用 MSVC):
    int foo() {

    named(label1) for(int i = 0 ; i < 10; i++)
    {
    if(some_condition)
    {
    break(label1); // here it's ok, the behavior is obvious
    }
    }

    break(label1); // it compiles fine without warning... but the behavior is pretty obscur!

    }
  • 它可能会破坏一些好看的代码。例如,由于范围问题,以下内容未编译。
    int foo() {

    named(label1) for(int i = 0 ; i < 10 ; i++)
    named(label2) for(int j = 0 ; j < 10 ; j++)
    if(i*j<15)
    cout << i*j << endl;
    else
    break(label2);
    }

  • 更安全的实现

    我试图解决所有这些问题以获得 的安全版本命名循环 .更一般地说,它也可以称为 易碎范围 因为它可以用于提前退出任何范围,而不仅仅是循环。

    这里是两个宏的定义 NAMEDBREAK :
        #define NAMED(bn)   if(const bool _YOU_CANNOT_USE_NAMED_BREAK_IF_YOU_ARE_OUTSIDE_##bn##_ = true)\
    goto _named_loop_identifier__##bn##_;\
    else\
    _break_the_loop_labelled_##bn##_:\
    if(true)\
    {}\
    else\
    if(! _YOU_CANNOT_USE_NAMED_BREAK_IF_YOU_ARE_OUTSIDE_##bn##_)\
    goto _break_the_loop_labelled_##bn##_;\
    else\
    _named_loop_identifier__##bn##_:\


    #define BREAK(bn) if(!_YOU_CANNOT_USE_NAMED_BREAK_IF_YOU_ARE_OUTSIDE_##bn##_){} \
    else goto _break_the_loop_labelled_##bn##_

    它看起来丑陋且笨重,因为它还避免了可能由 MSVC 或 GCC 生成的一些警告,如“未使用的变量”、“未引用的标签”或“建议显式大括号”。此外,如果使用不当,它不应编译,在这种情况下,错误消息将是可以理解的。例如 :
        NAMED(loop1) for(int i = 0 ; i < 10; i++) {
    NAMED(loop2) for(int j = 0 ; j < i ; j++) {
    cout << i << "," << j << endl;
    if(j == 5) {
    BREAK(loop1); // this one is okay, we exit the outer loop
    }
    }
    BREAK(loop2); // we're outside loop2, this is an error
    }

    前面的代码不会编译,第二个的编译器错误信息 BREAK :'_YOU_CANNOT_USE_NAMED_BREAK_IF_YOU_ARE_OUTSIDE_loop2_`,这是非常明确的。

    例子

    在问我的问题之前,我提供了两个例子来说明这些结构的(相对)有用性:
    break一个外循环:
         NAMED(myloop) for(int i = 0 ; i < rows; i++) {
    for(int j = 0 ; j < cols ; j++) {
    if(some_condition) {
    BREAK(myloop);
    }
    }
    }

    退出特定范围:
    NAMED(myscope1) {
    cout<< "a";
    NAMED(myscope2)
    {
    cout << "b";
    NAMED(myscope3)
    {
    cout << "c";
    BREAK(myscope2);
    cout << "d";
    }
    cout << "e";
    }
    cout <<"f";
    }

    此代码打印: abcf .

    我的问题

    在定义我的问题之前,我必须定义它不是什么,因为我不想看到我的主题在 10 分钟内结束。

    不是 “这是个好主意吗?”,也不是“你觉得怎么样?”甚至“它有用吗?”,因为 stackoverflow 似乎不是一个讨论场所。无论如何,我已经知道答案:“宏是邪恶的”、“Goto 是邪恶的”和“改用 lambdas”。

    相反,我的问题是关于技术正确性和针对编程错误的鲁棒性。我希望这个构造尽可能安全。
  • 用户是否有可能滥用它并且仍然能够编译?
    我试图修复原始实现的明显问题,但 C++ 非常复杂,也许我错过了什么?
  • 它可以默默地破坏一些好看的代码吗? 这是我主要关心的问题。它是否会干扰其他 C++ 功能(异常处理、析构函数调用、其他条件语句或其他任何东西...)?

  • 我的目标是证明这种结构本质上并不危险。我已经知道在实际代码中使用它是一个非常糟糕的主意,因为其他程序员可能不清楚它,但是在个人项目中使用它是否足够安全?

    编辑: bool 变量现在是 const (感谢 Jens Gustedt)。我会尝试更换 if来自 for稍后检查它可以在像这样使用时删除虚假警告:
    if(true)
    BREAK(label);

    EDIT2:正如 JensGustedt 所注意到的, if 中的变量声明C 语言中不允许使用语句(仅限 C++)。用循环替换它的另一个原因。

    最佳答案

    我想你已经测试过了,但是......不是bool您在 NAMED(bn) 中声明的变量稍后在同一块中仍然可用它声明的 if 语句是否存在? (:除非是这样,否则您的习语将不起作用。:)

    我可以看到这是安全的:

    {
    NAMED(one) { ... }
    }
    BREAK(one);

    编译器会在 BREAK(nb);上大惊小怪线

    但这看起来仍然不安全:
    {
    NAMED(bn) { ... }
    BREAK(bn);
    }

    不安全,因为编译器可能仍然接受定义的变量而不是大惊小怪。但它可能会形成一个无限循环,从而无声地破坏您的程序。

    -杰西

    PS:不会干扰 try..finallyfinally块被定义为无论您如何退出 try 都会执行堵塞。所以只要你不是 正在尝试 避免 finally块,你没事。

    P(PS)S:我看到的与其他结构唯一真正奇怪的交互是这样的:
    #if DEBUG
    NAMED(bn)
    #endif
    while(true)
    {
    BREAK(BN);
    }

    这是病态的! ;-D 这会在 DEBUG 中编译正常,但在 RELEASE 中会出现编译器错误。

    关于c++ - C/C++ 中可中断的命名范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11072212/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com