命名循环成语:危险吗?

我在C ++中读过一篇关于“命名循环习语”的文章: http : //en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Named_Loop

这个成语允许我们写这样的东西:

named(outer) for(int i = 0 ; i < rows ; ++i) { named(inner) for(int j = 0 ; j < cols ; ++j) { if(some_condition) break(outer); // exit the 'outer' loop } } 

这样的构造已经作为许多语言的核心特征存在,例如Java。

根据这篇文章,它可以通过定义两个邪恶的宏来用C ++实现:

 #define named(blockname) goto blockname; \ blockname##_skip: if (0) \ blockname: #define break(blockname) goto blockname##_skip; 

我知道很多人都想放弃使用goto 。 我个人发现它在极少数情况下很有用,特别是当我想break一堆嵌套循环时。 这个成语在我看来是一个更清晰的解决方案,但它可以在实际代码中使用它吗?

在本文的讨论页面上,可以阅读:

“不要这样做。你最终会陷入地狱”

所以我的问题是: 使用命名循环习语的缺点什么? 危险吗 ? 如果是,为什么?

奖金问题:是否有可能同样实施命名continue (我认为不可能使用named(...) for(...;...;...) {}语法,但谁知道?)

编辑:我同意你的意见,重新定义关键字是令人讨厌的。 那么使用#define breakLoop()呢?

正如评论所述,#defining break是有问题的。 我们假设您使用其他东西。

我仍然认为这很危险。 对于C ++程序员来说,这是一种非常不寻常的习惯,因此他们不太可能理解,因此他们可能会做出重大改变。 鉴于完成同样事情的方法不那么令人惊讶 – 因而也就是那么危险 – 我会建议不要这样做。

考虑将循环放在函数或lambda中。 然后你可以return打破外循环。 作为一个好处,您可以返回有关过早退出的信息,这可能对外部代码有用。

我发现了一些问题。

首先,您要定义一个与该语言的保留字名称相同的宏。 即使你的编译器不抱怨,它也容易出错,而且(IMO,至少)是危险的。

其次,我总是犹豫是否以编程方式创建标签。 即使您在同一范围内意外创建了两个具有相同名称的标签,您的编译器也可能会抱怨,如果没有程序员解析这些宏(这部分地违背了额外抽象的目的),它可能不会轻易理解它生成的错误消息。 。

可能我的主要问题是宏引入了与普通语言语法不同的东西。 named(...)行不以分号结尾,也不跟{ ... }块一起。 添加任何类型的新语法为开发人员混淆和意外滥用打开了大门。

总的来说,我有点像命名循环的想法,但这不是你想用宏创建的东西。 这是一种真正需要由语言本身提供的机制。 使用C或C ++时,使用手动创建的标签和goto更干净,更安全,更易于维护。 明确而不是隐藏宏背后发生的事情几乎总是更好。