【问题标题】:Using unset member variables within a class or struct在类或结构中使用未设置的成员变量
【发布时间】:2012-09-02 07:35:01
【问题描述】:

在使用未设置的局部变量或在初始化之前直接访问类或结构的成员时,捕获一些非常明显的错误非常好。在 Visual Studio 2008 中,您会在编译时收到“使用未初始化的局部变量”警告,并在调试时访问时遇到运行时检查失败。

但是,如果您通过其中一个函数访问未初始化结构的成员变量,您不会收到任何警告或断言。显然,最简单的解决方案是不要那样做,但没有人是完美的。

例如:

struct Test
{
    float GetMember() const { return member; }
    float member;
};
Test test;
float f1 = test.member;      // Raises warning, asserts in VS debugger at runtime
float f2 = test.GetMember(); // No problem, just keeps on going

这让我感到惊讶,但它有一定的意义——编译器不能假设在未使用的结构上调用函数是错误的,否则你将如何初始化或构造它?任何更高级的东西都会很快带来许多其他复杂性,以至于它不会费心分类哪些函数可以调用以及何时调用,尤其是作为调试帮助。我知道我可以在类本身中设置自己的断言或错误检查,但这会使一些更简单的结构复杂化。

不过,在函数调用的上下文中,它难道不知道GetMember() 内部member 还没有初始化吗?我假设它不仅依赖于静态编译时推导,考虑到它在执行期间引发的Run-Time Check Failure #3,所以根据我目前对它的理解,应用相同的检查似乎是合理的。这只是这个特定编译器/调试器 (Visual Studio 2008) 的限制,还是更多地与 C++ 的工作方式有关?

【问题讨论】:

  • Is this just a limitation of this specific compiler/debugger (Visual Studio 2008), or more tied to how C++ works? 标准不禁止使用未初始化的变量。这是 MSVC 调试功能。
  • @ForEveR 你不能使用未初始化的变量作为右值。
  • @LuchianGrigore “不能”是什么意思?程序格式正确,但它是UB,对。但这并不意味着“你不能”。
  • @ForEveR 是真的。但是您必须同意该评论弊大于利。我的意思是,说它没问题,只是因为它是一个格式良好的程序,但忽略了它是 UB(更糟糕的是,因为不需要诊断)......
  • @ForEveR 我知道你的意思,我只是说措辞可以更好。说它不被禁止有点暗示它没关系。至少对我来说。

标签: c++ visual-studio debugging visual-studio-2008


【解决方案1】:

您可能会注意到警告是关于 test 未初始化。这就是为什么警告和运行时失败仅适用于该行

float f1 = test.member;

这会导致未定义的行为,并且,至少在调试模式下,MSVS 会进行一些检查并且能够崩溃(在发布中,该错误可能会被隐藏,并且您最终会在 @987654323 中得到一个虚假值@)。

然而,下一行不会直接导致 UB。 f1 不会被读取,它的任何数据成员(直接)也不会被读取。调用了一个方法,编译器无法知道该成员函数会在未初始化的对象上产生 UB。该函数可以只在屏幕上打印一些内容,而不读取任何成员,这样就可以了。好吧,编译器在理论上可以知道,因为它看到了代码,但它并没有深入挖掘。静态代码分析器可能会提醒您该问题。

【讨论】:

  • @DougKavendek 如果您查看反汇编,您会看到插入了检查因为编译器看到了未初始化的变量。在那个微不足道的情况下,它只会变得复杂(或者非常慢,即使在调试模式下)。
  • 啊哈,我想我认为它是在运行时使用某种未初始化的哨兵初始值进行动态检查,但我什至没有想过要查看反汇编。我想我明白现在发生了什么。很高兴用事实代替我的假设!
猜你喜欢
  • 1970-01-01
  • 2014-05-22
  • 2018-03-06
  • 2017-02-07
  • 1970-01-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
相关资源
最近更新 更多