Visual Studio 2010 C ++是否完全支持类内const变量? [英] Does Visual Studio 2010 C++ Fully Support in-Class const Variables?

查看:250
本文介绍了Visual Studio 2010 C ++是否完全支持类内const变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题与以前提出的问题密切相关 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产生这个链接错误:

 错误LNK2005: public:static int const B :: m_b(?m_b @ B @@ 2HB)已经在a.obj中定义
1> a.exe:致命错误LNK1169:找到一个或多个乘法定义符号

然而GCC编译,链接并成功运行代码。

以下是有问题的代码:

文件a.cpp:

  #include< iostream> 
#includea.h

const int B :: m_b;

int main()
{
B b;
std :: cout<< b.m_b;
返回0;
}

文件啊:

  #pragma once 

#includebh

文件b.cpp:

  #includebh

文件bh:

  #pragma once 

class B {
public:
static const int m_b = 100;
};

以下是链接器选项(默认VS10控制台程序):

  / OUT:a.exe
/ NOLOGOkernel32.libuser32.libgdi32.libwinspool.lib comdlg32.libadvapi32.libshell32.libole32.liboleaut32.libuuid.libodbc32.libodbccp32.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/ FaDebug \/ FoDebug\/Fd\"Debug\vc100.pdb/ Gd
/ analyze- / errorReport:queue

再一次地,这与GCC(g ++ a.cpp b.cpp)建立,链接并成功运行。我提供的代码是完整的,所以它可以被复制,粘贴和运行。 解决方案

头文件中数据的模板定义,因为在链接时你会得到多个定义错误。这个变量是一个成员变量,一个静态成员变量还是一个常量静态成员变量,根本不会改变它。



将定义放在一个编译单元中,就像你对任何其他单身人士一样。






这实际上看起来像一个Visual C ++错误。如果您显示完整的错误消息,即


b.obj:error LNK2005:public:static int const B :: m_b(?m_b @ B @@ 2HB)已在a.obj
中定义a.exe:致命错误LNK1169:找到一个或多个乘法定义的符号




如果编译器工作正常,该符号将不会在b.obj中的任何位置定义。




此外,尝试使用 __ declspec(selectany)告诉我们编译器知道这不是一个定义:


r:\16404173\bh(3):错误C2496:'B :: m_b':'selectany'只能应用于
带外部数据项link






最后,Visual C ++明确定义了符号(错误地) p>

R:\ 16404173> dumpbin / symbols b.obj
Microsoft(R)COFF / PE Dumper版本10.00.40219.01
复制右(C)微软公司。保留所有权利。



 文件转储b.obj 

文件类型:COFF OBJECT

COFF符号表
000 00AB9D1B ABS类型静态| @ comp.id
001 00000000 SECT1类型静态| .drectve
段长度2F,#relocs 0,#linenums 0,校验和0
003 00000000 SECT2类型静态| .debug $ S
段长度64,#relocs 0,#linenums 0,校验和0
005 00000000 SECT3类型静态| .rdata
段长度4,#relocs 0,#linenums 0,校验和B4446054,选择2(选择任意)
007 00000000 SECT3 notype外部| ?m_b @ B @@ 2HB(public:static int const B :: m_b)


此外,我们已经看到它已被标记为 selectany 。但是在具有实际定义的编译单元中:


 段长度4,#relocs 0,# linenums 0,校验和B4446054 
229 00000000 SECTB9 notype外部| ?m_b @ B @@ 2HB(public:static int const B :: m_b)


(挑选任何)注释消失。哪一个是正确的,这是一个权威的变量定义。



变量出现在 b.obj selectany 注释来实现简单的情况(在头文件中初始化),但是当提供真实的定义时,这种骇人的解决方法就会崩溃。

b
$ b


最后,在真实定义中添加 __ declspec(selectany),在a.cpp ,围绕链接错误工作。但是恐怕这个符号仍然会被链接器优化掉,并且在调试过程中不可用。您可以暂时使用 / OPT:NOREF 来避免这种情况(但会使您的可执行文件膨胀,因此请在发货前再次关闭该选件)。


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).

这篇关于Visual Studio 2010 C ++是否完全支持类内const变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆