这个问题与之前提出的一个问题密切相关here .
为了让 Visual Studio 2010 C++ 调试器解析类内初始化的 const 变量,必须提供该变量的全局定义。
例如
类定义如下:
class B{
public:
static const int m_b=100;
};
这是成员的全局范围定义:
const int B::m_b;
如果没有全局定义,代码可以工作,但调试器无法在 B 的方法中看到 m_b。
然而,这会导致另一个问题。在重要的头文件包含安排中(下面给出完整代码),Visual Studio 会产生此链接错误:
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
但是 GCC 编译、链接和运行代码成功。
这里是有问题的代码:
文件 a.cpp:
#include <iostream>
#include "a.h"
const int B::m_b;
int main()
{
B b;
std::cout << b.m_b;
return 0;
}
文件a.h:
#pragma once
#include "b.h"
文件 b.cpp:
#include "b.h"
文件 b.h:
#pragma once
class B {
public:
static const int m_b = 100;
};
以下是链接器选项(默认 VS10 控制台程序):
/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
以下是编译器选项(默认 VS10 控制台程序):
/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
同样,这可以使用 GCC ( g++ a.cpp b.cpp ) 成功构建、链接和运行。我提供的代码是完整的,因此可以复制、粘贴和运行。
最佳答案
您不应该将数据的非模板定义放在头文件中,因为您会在链接时遇到多个定义错误。无论变量是成员变量还是静态成员变量还是 const 静态成员变量都不会改变这一点。
将定义放在一个编译单元中,就像您对任何其他单例所做的那样。
这实际上看起来像一个 Visual C++ 错误。如果您显示完整的错误消息,即
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
如果编译器工作正常,则该符号不会在 b.obj 中的任何位置定义。
此外,尝试使用 __declspec(selectany)
告诉我们编译器知道这不是定义:
r:\16404173\b.h(3) : error C2496: 'B::m_b' : 'selectany' can only be applied to data items with external linkage
最后,Visual C++ 显然在定义符号(不正确):
R:\16404173>dumpbin/symbols b.obj Microsoft (R) COFF/PE 转储程序版本 10.00.40219.01 版权所有 (C) Microsoft Corporation。保留所有权利。
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)
此外,我们看到它已经被标记为selectany
。但是在具有实际定义的编译单元中:
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)
(pick any)
注释消失了。没错,这是对变量的权威定义。
变量出现在b.obj
中是完全错误的。编译器通过使用 selectany
注释使简单的情况(在头文件中初始化)工作,但是当提供真正的定义时,这种骇人听闻的解决方法就会失败。
最后,在 a.cpp 中的真实定义上添加 __declspec(selectany)
可以解决链接错误。但恐怕该符号仍会被链接器优化掉,并且在调试期间不可用。您可以暂时使用 /OPT:NOREF
来避免这种情况(但它会使您的可执行文件膨胀,因此在发布前再次关闭该选项)。
关于c++ - Visual Studio 2010 C++ 是否完全支持类内 const 变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16404173/