C++ 中的参考初始化
大家好!
检查我自己的代码,我发现了这一有趣的行:
const CString &refStr = ( CheckCondition() ) ? _T("foo") : _T("bar");
现在我完全不知所措,无法理解为什么它是合法的。据我了解,必须使用右值或左值初始化 const 引用。未初始化的引用不能存在。但 ()?运算符在为引用赋值之前执行 CheckCondition() 函数。我现在可以看到,当执行 CheckCondition() 时, refStr 存在,但仍未初始化。如果 CheckCondition() 抛出异常或使用 goto 语句传递控制会发生什么?它会使引用未初始化还是我遗漏了什么?
Greetings, everyone!
Examining my own code, I came up to this interesting line:
const CString &refStr = ( CheckCondition() ) ? _T("foo") : _T("bar");
Now I am completely at a loss, and cannot understand why it is legal. As far as I understand, const reference must be initialized, either with r-value or l-value. Uninitialized references cannot exist. But ()? operator executes a CheckCondition() function before it assigns value to the reference. I can see now, that while CheckCondition() is executed, refStr exists, but still not initialized. What will happen if CheckCondition() will throw an exception, or pass control with a goto statement? Will it leave the reference uninitialized or am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
你错过了一些东西 - 它是完全合法的代码,事实上,这样的代码是条件运算符最常见和最好的用途之一。认为编译器必须在内部按照代码在页面上布局的顺序执行操作的想法总是错误的 - 它完全可以自由地评估条件运算符(这只是另一个表达式),然后使用结果来执行初始化。
至于 goto,无法在初始化中使用 goto。如果抛出异常,则该引用将被视为从未创建过。
You are missing something - it is completely legal code, and in fact such code is one of the commonest and best uses of the conditional operator. It's always a mistake to think that the compiler must internally do things in the same order that the code is layed out on the page - it is perfectly at liberty to evaluate the conditional operator (which is justv another expression) and then use the result to perform the initialisation.
As for a goto, there is no way of using one in an initialisation. And if an exception is thrown, the reference is deemed never to have been created in the first place.
更简单的示例:
const int x = foo();
这个常量也必须初始化,为此需要调用
foo()
。这按照必要的顺序发生:x 仅当 foo 返回时才存在。回答您的其他问题:如果
foo()
会抛出
,异常将被某处的catch()
捕获。显然,catch()
的try{}
块包围了const int x = foo();
。因此 const int x 已经超出了范围,并且它从未获得值也无关紧要。如果没有catch
来捕获异常,您的程序(包括const int x
)就会消失。C++ 没有随机的
goto
。它们可以在 foo() 内跳转,但这并不重要;foo()
仍然需要返回。Simpler example:
const int x = foo();
This constant too has to be initialized, and for that
foo()
needs to be called. That happens in the order necessary: x comes into existance only when foo returns.To answer your additional questions: If
foo()
wouldthrow
, the exception will be caught by acatch()
somewhere. Thetry{}
block for thatcatch()
surroundedconst int x = foo();
obviously. Henceconst int x
is out of scope already, and it is irrelevant that it never got a value. And if there's nocatch
for the exception, your program (includingconst int x
) is gone.C++ doesn't have random
goto
's. They can jump withinfoo()
but that doesn't matter;foo()
still has to return.不幸的是,在初始化期间可以做一些有趣的事情。您也可以编写
or ,
我想当编译器从左到右进行时, a 确实在右侧的范围内,所以从技术上讲,您应该能够使用它,并且最多可以使用它可以警告:
“ComeauTest.c”,第 9 行:警告:在设置变量“a”的值之前使用它
当然,这只会导致未定义的行为,就像使用任何未初始化的变量一样。
您的示例很好,因为您在初始化之前不使用引用。
Unfortunately funny things can be done during initialization. You could have also written
or for the matter
I suppose as the compiler proceeds from left to right, a is indeed in scope on the right side, so technically you should be able to use it and at best it can warn:
"ComeauTest.c", line 9: warning: variable "a" is used before its value is set
Naturally this can only result in undefined behavior as with using any uninitialized variable.
Your example is fine, since you don't use the reference before it has been initialized.
从语言律师的角度来看,这是错误的。在初始化期间,
refStr
还不存在。我猜你的可视化调试器给了你误导性的提示。如果初始化中的代码导致错误情况,
refStr
将不存在,并且永远不会存在。From a language lawyer point of view, this is wrong. During initialization,
refStr
doesn't exist yet. I'd guess that your visual debugger is giving you misleading hints.If the code inside the initialization leads to an error condition,
refStr
will not exist, and will not ever have existed.这是完全合法的。要么成功完成并且引用绑定到有效对象,要么抛出异常并且控制权转移到块之外并且引用不再在范围内,因此没有人再关心它。
This is completely legal. Either this finishes successfully and the reference is bound to a valid object or an exception is thrown and control is transferred outside the block and the reference is no longer in scope so noone cares of it anymore.
异常会将您带到无法访问 refStr 的地方,并且您无法从那里转到它所在的地方。如果 goto 是函数,则它无法退出 CheckCondition();如果 goto 是宏,则您将无法使用 goto。 longjmp() 与异常具有相同的效果:您将转到 refStr 不可访问的地方。
An exception will bring you to a place where refStr isn't accessible and you can't go to a place where it is from there. A goto won't be able to get out of CheckCondition() if it is a function, and you won't be able to use a goto if it is a macro. A longjmp() will have the same effect as an exception: you'll go to a place where refStr isn't accessible.