以下内容是无意义的,但可以干净地编译g++ -Wall -Wextra -Werror -Winit-self
(我测试了GCC 4.7.2和4.9.0):
#include <iostream>
#include <string>
int main()
{
for (int ii = 0; ii < 1; ++ii)
{
const std::string& str = str; // !!
std::cout << str << std::endl;
}
}
所标记的线!!
导致未定义的行为,但未被 GCC 诊断。然而,注释掉for
这条线让海湾合作委员会抱怨:
error: ‘str’ is used uninitialized in this function [-Werror=uninitialized]
我想知道:为什么GCC在这里这么容易被愚弄?当代码不在循环中时,GCC 知道它是错误的。但是将相同的代码放在一个简单的循环中,GCC 就不再理解了。这让我很困扰,因为当我们在 C++ 中犯下愚蠢的错误时,我们非常依赖编译器来通知我们,但在看似微不足道的情况下它却失败了。
奖金琐事:
- 如果你改变
std::string
to int
and打开优化,GCC 即使使用循环也会诊断错误。
- 如果您使用以下命令构建损坏的代码
-O3
,GCC 从字面上调用 ostream 插入函数,并使用字符串参数的空指针。如果您认为如果没有进行任何不安全的转换,就不会受到空引用的影响,请再想一想。
我已为此提交了一个 GCC 错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63203 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63203- 我仍然想更好地了解出了什么问题以及它如何影响类似诊断的可靠性。
我仍然想更好地了解出了什么问题以及它如何影响类似诊断的可靠性。
与 Clang 不同,GCC 没有检测自初始化引用的逻辑,因此在这里获取警告依赖于检测未初始化变量的使用的代码,这是相当不稳定且不可靠的(请参阅更好的未初始化警告 https://gcc.gnu.org/wiki/Better_Uninitialized_Warnings供讨论)。
With an int
编译器可以发现你写了一个未初始化的int
到流,但带有std::string
类型表达式之间显然有太多抽象层std::string
并得到const char*
它包含,并且 GCC 无法检测到该问题。
例如只要您启用一些优化,GCC 就会对变量声明和使用之间代码较少的更简单示例发出警告:
extern "C" int printf(const char*, ...);
struct string {
string() : data(99) { }
int data;
void print() const { printf("%d\n", data); }
};
int main()
{
for (int ii = 0; ii < 1; ++ii)
{
const string& str = str; // !!
str.print();
}
}
d.cc: In function ‘int main()’:
d.cc:6:43: warning: ‘str’ is used uninitialized in this function [-Wuninitialized]
void print() const { printf("%d\n", data); }
^
d.cc:13:19: note: ‘str’ was declared here
const string& str = str; // !!
^
我怀疑这种缺失的诊断只会影响少数依赖启发式方法来检测问题的诊断。这些将给出以下形式的警告“may未初始化时使用”或“may违反严格的别名规则”,并且可能会出现“数组下标高于数组边界”警告。这些警告不是 100% 准确,并且像循环(!)这样的“复杂”逻辑可能会导致编译器放弃尝试分析代码并失败进行诊断。
恕我直言,解决方案是在初始化时添加对自初始化引用的检查,而不是依赖于稍后使用时检测它是否未初始化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)