9

This question is closely related to a subsequently asked question here.

The method of defining in-class constants is described here by Stroustrup.

When I follow Stroustrup's method I see the expected results. However, in Visual Studio 2010, the debugger cannot resolve a static const class member within that class's scope. Here is what I mean:

#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();
}

When the debugger is in showA() the "watch" window reports:

Error: Symbol "Foo::A" not found

I'd like to emphasize that the program does behave as expected i.e. the output is:

showA = 50

and the program returns 0.

Can anyone else reproduce this with Visual Studio 2010? Is this a bug in the debugger?

10
  • 1
    Notice, that you are missing a definition for your A static data member Commented May 3, 2013 at 19:01
  • It's inlined, to the OP's point Commented May 3, 2013 at 19:04
  • Is optimization enabled? Is the class inside a namespace? Commented May 3, 2013 at 19:07
  • 1
    @Andy Not if it's inlined. As the Stroustrup article, and dauphic's answer points out, the static definition is optional. I just tested both ways in VS and the static def'n isn't required with the inline initialization. Commented May 3, 2013 at 19:16
  • 1
    @AndyProwl Thanks again - SO at it's best here Commented May 4, 2013 at 14:45

3 Answers 3

7

You could add a definition for your static data member at global namespace scope:

const int Foo::A;

Adding the static data member definition, which is not necessary but allowed, seems to solve your problem.

I tested this on a debug build with VS2010, and the value of A is correctly displayed in the debug window when the definition is present (while an error message is reported when the definition is missing, consistently with what you mention).

Sign up to request clarification or add additional context in comments.

11 Comments

Thank you for quoting the standard. The answer to this question with 111 up-votes states that "initializ[ations] inside class definition[s] [are] only allowed with integral and enum types". And, the Stroustrup article seems to imply that the global definition is only required if you need to access the member's address. Add the fact that the code "works-as-expected" with VS10 and GCC/Cygwin, and I bet a lot of people would not realize the global definition is still needed. +1
@user2141130: Glad that helped, indeed it is not obvious that a definition is still required
It isn't odr-used; the program is ok. But there is no definition for the debugger to find.
@user2141130: That answer was posted before C++11 changed the rules -- now other types can be initialized inside the class. And Stroustrup's statement that the global definition is not always required is still correct.
@BenVoigt: OK. I must confess I haven't managed yet to concretely decipher 3.2p3, so my understanding of odr-used is limited. I will trust you and edit the answer, but it would be great if you could explain a bit which part of 3.2p3 makes A not odr-used (I understand it has something to do with the "unless" part, but that first paragraph is just confusing to me).
|
4

This isn't a bug. The compiler can (and almost always will) optimize out static constant basic types. Instead of allocating storage for A, the compiler is just inlining the value of A into the compiled instructions.

Because A isn't stored anywhere, it has no address, so the debugger cannot view it.

2 Comments

There is a bug here, although inlining the value isn't it. The compiler actually does emit a definition whether or not the code contains one (that's the bug) even if every use was inlined. And then the linker removes the definition since nothing depends on its presence.
It seems to me like with /Od flag it must not optimize anything
2

Visual C++ erroneously provides a weak definition (evidence provided in this answer) based on the declaration inside the class, despite clear language in the Standard:

The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator.

According to the another rule in the Standard, no definition is needed if the member isn't odr-used.

Whether there's an explicit definition or weak definition erroneously provided by Visual C++ makes no difference however. If the member isn't odr-used, the linker will not see any references to it and will remove it, leaving the debugger confused about whether it ever existed. With the Microsoft linker, you can inhibit this optimization using /OPT:NOREF.

Ultimately that's not something you want to do in production code, though, since you'll have all kinds of vestigial stuff from the standard library left over in your application. But for temporary use during debugging that's a reasonable setting.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.