This question is closely related to a question that was previously asked here.
In order for the Visual Studio 2010 C++ debugger to resolve in-class-initialized const variables, a global definition for the variable must be supplied.
e.g.
Here is the class definition:
class B{
public:
static const int m_b=100;
};
Here is the global scope definition of the member:
const int B::m_b;
Without the global definition the code works but the debugger cannot see m_b within B's methods.
However, this leads to another problem. In non-trivial header file inclusion arrangements (full code given below), Visual Studio produces this link error:
error LNK2005: "public: static int const B::m_b" (?m_b@B@@2HB) already defined in a.obj
1>a.exe : fatal error LNK1169: one or more multiply defined symbols found
However GCC compiles, links, and runs the code successfully.
Here is the code in question:
file a.cpp:
#include <iostream>
#include "a.h"
const int B::m_b;
int main()
{
B b;
std::cout << b.m_b;
return 0;
}
file a.h:
#pragma once
#include "b.h"
file b.cpp:
#include "b.h"
file b.h:
#pragma once
class B {
public:
static const int m_b = 100;
};
Here are the linker options (default VS10 console program):
/OUT:"a.exe"
/NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib"
/MANIFEST
/ManifestFile:"Debug\a.exe.intermediate.manifest"
/ALLOWISOLATION
/MANIFESTUAC:"level='asInvoker' uiAccess='false'"
/DEBUG
/PDB:"Debug\a.pdb"
/PGD:"Debug\a.pgd"
/TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
Here are the compiler options (default VS10 console program):
/ZI /nologo /W3 /WX- /Od /Oy- /D "_MBCS" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t
/Zc:forScope /Fp"Debug\sndbx.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd
/analyze- /errorReport:queue
Again, this builds, links, and runs successfully with GCC ( g++ a.cpp b.cpp ). The code I've supplied is complete so it can be copied, pasted, and run.
You shouldn't put non-template definitions of data in header files, because you will get multiple definition errors at link time. Whether the variable is a member variable or a static member variable or a const static member variable doesn't change this at all.
Put the definition in exactly one compilation unit, just like you would for any other singleton.
This actually looks like a Visual C++ bug. It would have helped considerably if you had shown the complete error message, namely
b.obj : error LNK2005: "public: static int const B::m_b" (?m_b@B@@2HB) already defined in a.obj
a.exe : fatal error LNK1169: one or more multiply defined symbols found
The symbol would not be defined anywhere in b.obj if the compiler were working right.
Furthermore, attempting to use __declspec(selectany)
tells us that the compiler knows this is not a definition:
r:\16404173\b.h(3) : error C2496: 'B::m_b' : 'selectany' can only be applied to
data items with external linkage
Finally, Visual C++ clearly is defining the symbol (incorrectly):
R:\16404173>dumpbin /symbols b.obj
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file b.obj
File Type: COFF OBJECT
COFF SYMBOL TABLE
000 00AB9D1B ABS notype Static | @comp.id
001 00000000 SECT1 notype Static | .drectve
Section length 2F, #relocs 0, #linenums 0, checksum 0
003 00000000 SECT2 notype Static | .debug$S
Section length 64, #relocs 0, #linenums 0, checksum 0
005 00000000 SECT3 notype Static | .rdata
Section length 4, #relocs 0, #linenums 0, checksum B4446054, selection 2 (pick any)
007 00000000 SECT3 notype External | ?m_b@B@@2HB (public: static int const B::m_b)
Furthermore, we see that it is marked as selectany
already. But in the compilation unit with the actual definition:
Section length 4, #relocs 0, #linenums 0, checksum B4446054
229 00000000 SECTB9 notype External | ?m_b@B@@2HB (public: static int const B::m_b)
The (pick any)
annotation is gone. Which is proper, this is an authoritative definition of the variable.
It's wrong for the variable to appear in b.obj
at all. The compiler makes the simple case (initialization inside header file) work by using the selectany
annotation, but this hackish workaround falls apart when a real definition is provided.
Finally, adding __declspec(selectany)
on the real definition, in a.cpp, works around the link error. But I'm afraid the symbol will still be optimized away by the linker and not available during debugging. You can temporarily use the /OPT:NOREF
to avoid this (but it will bloat your executable, so turn that option off again before shipping).
According to what clang will accept, the static const variable initialisation must happen in the definition rather than the declaration.
Therefore in your header you want this:
class B{
public:
static const int m_b;
};
And then the definition in your cpp should be like this:
const int B::m_b = 100;