考虑这段在 Visual Studio 2008 下测试的代码(使用 CString,因为它在未构造时很熟悉且易于查看,但该类没有什么特别之处):
CString DoSomething( const CString& sString )
{
return sString;
}
CString sTest1 = DoSomething( sTest1 ); // Compiles (no warnings), fails at runtime
CString sTest2( DoSomething( sTest2 ) ); // Doesn't compile
CString sTest3; sTest3 = DoSomething( sTest3 ); // Compiles, self-assignment, works
据我了解 C++ 标准,只要有适当的构造函数(默认情况下,将生成与第一个测试相同的构造函数),Test1 可以自动编译为 Test2 作为编译时优化。但值得注意的是,该行为与 Test3 不同,后者可以正常工作。
现在我明白为什么 Test1 不起作用,为什么 Test2 不能编译。我好奇的是为什么 Test1 首先可以编译?这是标准允许的、开放解释的、VS2008 编译器的缺陷、使用前初始化静态检查的缺陷还是什么?在这种情况下,有没有办法强制编译器至少发出警告(Test1 在 VS2008 下似乎以最大警告级别编译干净)? C++ 规范允许这种构造的理由是什么?
编辑:或者,有什么方法可以强制编译器将 Test1 编译为 Test2 (从而触发错误)?
编辑为 Test2 添加逐字错误消息: 错误 C2065:'sTest2':未声明的标识符
您在 sTest1 中看到的行为在 C++ 标准中未定义。 这很奇怪而且错误,但它可以在一些编译器上编译。
有关更多详细信息,请参阅 litb 在以下线程上的回答:在初始化对象之前在对象上运行方法?
这几天有几个相关现象的提问。
我的理解是,即使 sTest1 没有初始化,它已经是一个有效的标识符(例如,在 C 中你可以调用 sizeof ),它只是没有内容。 因此,当您调用 DoSomething 时,您正在传递对未初始化变量的引用,这是合法但危险的。
我猜测返回是运行时的问题,因为您正在尝试对本质上应该是字符串的未初始化内存空间进行按值返回(复制构造函数)。根据 CString 的存储方式,代码可能会查找空终止符或表示已分配字节数的内容。