1

大家好!

检查我自己的代码,我想到了这个有趣的行:

const CString &refStr = ( CheckCondition() ) ? _T("foo") : _T("bar");

现在我完全不知所措,无法理解为什么它是合法的。据我了解,必须使用 r 值或 l 值初始化 const 引用。未初始化的引用不能存在。但 ()?运算符在将值分配给引用之前执行 CheckCondition() 函数。我现在可以看到,在执行 CheckCondition() 时, refStr 存在,但仍未初始化。如果 CheckCondition() 会抛出异常,或者使用 goto 语句传递控制,会发生什么?它会留下未初始化的引用还是我错过了什么?

4

6 回答 6

6

你遗漏了一些东西——它是完全合法的代码,事实上这样的代码是条件运算符最常见和最好的用途之一。认为编译器必须按照代码在页面上的布局顺序在内部执行操作总是错误的 - 完全可以自由地评估条件运算符(这只是另一个表达式)然后使用结果执行初始化。

至于 goto,没有办法在初始化中使用它。如果抛出异常,则认为从一开始就从未创建过引用。

于 2009-08-20T09:40:00.793 回答
5

更简单的例子:const int x = foo();

这个常量也必须被初始化,为此foo()需要被调用。这以必要的顺序发生: x 仅在 foo 返回时才存在。

要回答您的其他问题: If foo()would throw,异常将被catch()某处捕获。显然包围的try{}块。因此已经超出了范围,并且它从未获得过价值是无关紧要的。如果没有例外,您的程序(包括)就消失了。catch()const int x = foo();const int xcatchconst int x

C++ 没有随机goto的。他们可以跳进去,foo()但这没关系;foo()仍然必须返回。

于 2009-08-20T10:04:01.523 回答
3

未初始化的引用不能存在。

不幸的是,在初始化期间可以做一些有趣的事情。你也可以写

const int& a = foobar(a) ? 1 : 2;

或就此而言

const int& a = a;

我想随着编译器从左到右进行,a 确实在右侧的范围内,所以从技术上讲,你应该能够使用它,并且充其量它可以发出警告:

“ComeauTest.c”,第 9 行:警告:变量“a”在其值设置之前使用

  const int& a = foobar(a) ? 1 : 2;
                        ^

自然,这只会导致未定义的行为,就像使用任何未初始化的变量一样。

您的示例很好,因为您在初始化之前不使用引用。

于 2009-08-20T10:38:12.003 回答
2

我现在可以看到,在执行 CheckCondition() 时, refStr 存在,但仍未初始化。

从语言律师的角度来看,这是错误的。在初始化期间,refStr还不存在。我猜你的视觉调试器会给你误导性的提示。

如果初始化中的代码导致错误条件,refStr则将不存在,并且永远不会存在。

于 2009-08-20T09:41:57.920 回答
2

这是完全合法的。要么成功完成并且引用绑定到有效对象,要么抛出异常并且控制转移到块之外并且引用不再在范围内,因此不再关心它。

于 2009-08-20T09:42:23.907 回答
0

异常会将您带到无法访问 refStr 的地方,并且您无法从那里前往它所在的地方。如果 goto 是函数,goto 将无法退出 CheckCondition(),如果它是宏,您将无法使用 goto。longjmp() 将具有与异常相同的效果:您将转到无法访问 refStr 的地方。

于 2009-08-20T09:52:47.787 回答