为什么全局 const 对象在每个翻译单元中都有唯一的副本,如何防止这种情况发生?

问题描述 投票:0回答:2

当我声明并初始化一个 const 对象时。

// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;

并且有两个cpp文件包含这个头文件。

// Unit1.cpp
#include "ConstClass.h"
#include "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}

// Unit2.cpp
#include "ConstClass.h"
#include "stdio.h"

void PrintInUnit2( )
{
    printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}

当我构建解决方案时,没有链接错误,如果 g_Const 是非常量基本类型,您将得到什么!

PrintInUnit1()和PrintInUnit2()显示两个编译单元中有两个地址不同的独立“g_Const”,为什么?

==============

我知道如何修复它。(使用 extern 关键字声明,并在一个 cpp 文件中定义它。)

我想知道为什么我在此示例中没有收到 redfined 链接错误。

c++ hyperlink global-variables constants
2个回答
9
投票

https://stackoverflow.com/a/6173889/1508519

命名空间范围内的 const 变量具有内部链接。所以他们是 基本上是两个不同的变量。没有重新定义。

3.5/3 [基本.链接]:

具有命名空间范围(3.3.5)的名称具有内部链接,如果它是 的名字

— 对象、引用、函数或函数模板 显式声明静态或,

— 显式声明为 const 的对象或引用,并且既不 显式声明为 extern 或之前声明为具有 external 连锁;或

— 匿名联合体的数据成员。

如果您希望它具有外部链接,请使用

extern


正如另一个答案中所述,头文件只是粘贴在 cpp 文件中。两个 cpp 文件中都包含相同的头文件,但它们是单独的翻译单元。这意味着变量的一个实例与另一实例不同。要让编译器知道您已在其他地方定义了该变量,请使用

extern
关键字。这可确保跨翻译单元仅共享一个实例。然而
extern const Test test
只是一个声明。你需要一个定义。只要在某个 cpp 文件中定义一次即可,在哪里定义它并不重要。您可以根据需要多次声明它(这很方便将其放在头文件中。)

举个例子:

常数.h

class Test
{
};

extern const Test test;

单元1.cpp

#include "Constant.h"
#include <iostream>

void print_one()
{ std::cout << &test << std::endl; }

单元2.cpp

#include "Constant.h"
#include <iostream>

void print_two()
{ std::cout << &test << std::endl; }

主.cpp

extern void print_one();
extern void print_two();

int main()
{
   print_one();
   print_two();
}

常数.cpp

#include "Constant.h"
const Test test = Test();

生成文件

.PHONY: all
all:
   g++ -std=c++11 -o test Constant.cpp Unit1.cpp Unit2.cpp main.cpp

5
投票

因为你把变量定义放在头文件中。包含头文件就像用文件内容替换它一样。所以,第一个文件:

// Unit1.cpp
#include "ConstClass.h"  // this will be replace with the content of ConstClass.h
#include "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}

将变成(编译前的预处理阶段之后):

// Unit1.cpp
// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}

第二个文件将是:

// Unit2.cpp
// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"

void PrintInUnit2( )
{
    printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}

如您所见,每个文件都有单独的变量

g_Const
(这只是针对您的代码的情况,可能根本没有变量,就像宏一样,请参阅我上一段中的解释)。

如果你想要的不是变量的定义而只是头文件中的声明,你应该在头文件中使用

extern
关键字:

extern const ConstClass g_Const;

然后可以将

g_Const
变量的定义放在
ConstClass.c


您的代码中有一些问题:

  • 您的
    g_Const
    定义中没有分配常量值,除非您想要默认值 (0),否则您必须在定义中为其分配常量值。
  • 在 printf 中,您获取 C++ 的
    const
    变量的地址。这实际上迫使编译器在堆栈中创建变量。如果您不获取地址,它可能能够推断出一个编译时数字,其行为类似于 C 中的宏(您可以直接将幻数放入使用
    const
    变量的代码中)。
© www.soinside.com 2019 - 2024. All rights reserved.