C++ 为什么';Visual Studio 2010调试器是否看到静态常量类成员?

C++ 为什么';Visual Studio 2010调试器是否看到静态常量类成员?,c++,visual-studio,gcc,compiler-construction,debuggervisualizer,C++,Visual Studio,Gcc,Compiler Construction,Debuggervisualizer,这个问题与后来提出的问题密切相关 Stroustrup描述了定义类内常量的方法 当我遵循Stroustrup的方法时,我看到了预期的结果。但是,在Visual Studio 2010中,调试器无法解析该类作用域内的静态常量类成员。 我的意思是: #include <iostream> class Foo { public: static const int A = 50; char arr[A]; void showA(); }; void Foo:

这个问题与后来提出的问题密切相关

Stroustrup描述了定义类内常量的方法

当我遵循Stroustrup的方法时,我看到了预期的结果。但是,在Visual Studio 2010中,调试器无法解析该类作用域内的
静态常量
类成员。 我的意思是:

#include <iostream>

class Foo {
   public:
    static const int A = 50;
    char arr[A];
    void showA();
};

void Foo::showA() {
    std::cout << "showA = " << A << "\n";
}

int main() {
    Foo f;
    f.showA();
}
我想强调的是,程序的行为确实符合预期,即输出为:

showA = 50
程序返回0


其他人能用VisualStudio2010复制这个吗?这是调试器中的错误吗?

这不是错误。编译器可以(而且几乎总是会)优化静态常量基本类型。编译器不是为
A
分配存储,而是将
A
的值内联到编译后的指令中

由于
A
未存储在任何位置,因此它没有地址,因此调试器无法查看它。

您可以在全局命名空间范围中为静态数据成员添加定义:

const int Foo::A;
添加静态数据成员定义似乎可以解决您的问题,这不是必需的,但却是允许的


我在VS2010调试版本上测试了这个值,当定义存在时,在调试窗口中正确地显示了<代码> A/<代码>的值(当定义丢失时,报告错误消息,与您提到的一致)。VisualC++在VisualC++中错误地提供了基于类内的声明,尽管标准中有明确的语言:

静态数据成员在其类定义中的声明不是定义,可能是除cv qualified
void
之外的不完整类型。静态数据成员的定义应出现在包含该成员的类定义的命名空间范围中。在命名空间范围的定义中,静态数据成员的名称应使用
运算符通过其类名限定

根据标准中的另一条规则,如果未使用odr,则不需要定义

是否存在Visual C++错误提供的明确定义或弱定义,但没有区别。如果成员未使用odr,链接器将看不到对它的任何引用,并将删除它,使调试器对它是否曾经存在感到困惑。使用Microsoft linker,您可以使用

/OPT:NOREF
禁止此优化


不过,最终这并不是您希望在生产代码中执行的操作,因为您的应用程序中会有来自标准库的各种残留内容。但对于调试期间的临时使用,这是一个合理的设置。

注意,您缺少
a
静态数据成员的定义。它是内联的,指向OP的点是否启用了优化?类是否在命名空间内?@Andy如果是内联的,则不在命名空间内。正如Stroustrup文章和Daupic的回答所指出的,静态定义是可选的。我刚刚在VS中测试了这两种方法,内联初始化不需要静态定义。@AndyProwl再次感谢-因此,在这里最好感谢您引用标准。111票赞成的回答指出,“类定义内的初始化只允许整数和枚举类型”。而且,Stroustrup文章似乎暗示,只有在需要访问成员地址时才需要全局定义。再加上VS10和GCC/Cygwin的代码“按预期工作”,我敢打赌很多人不会意识到仍然需要全局定义+1@user2141130:很高兴这有帮助,事实上,现在还不清楚是否需要一个定义,因为没有使用odr;程序还可以。但是调试器找不到任何定义。@user2141130:这个答案是在C++11更改规则之前发布的——现在其他类型可以在类内初始化。Stroustrup关于不总是需要全局定义的陈述仍然是正确的。@BenVoigt:OK。我必须承认,我还没有具体解释3.2p3,所以我对odr的理解是有限的。我相信你并编辑答案,但如果你能解释一下3.2p3的哪个部分使
a
没有使用odr,那就太好了(我知道它与“除非”部分有关,但第一段让我很困惑)。这里有一个bug,尽管内联值不是它。编译器实际上会发出一个定义,不管代码是否包含一个定义(这就是bug),即使每次使用都是内联的。然后链接器删除定义,因为任何东西都不依赖于它的存在。
const int Foo::A;