C++在头文件中定义const变量或static变量

问题引入

  代码中总能看到有的人喜欢在头文件中定义const变量,或者在头文件中定义static变量。最常见的就是在头文件中定义字符串,例如在头文件def.h中定义变量:

// defs.h
static std::string s_str = "Static"; 
const std::string kStr = "Const";

这样写就可以在需要用到该字符串的地方引入这个头文件。

  在源文件中引入头文件相当于直接把头文件的内容拷贝到原文件中,如果引入这个头文件后,将会在每个引入的源文件中重复定义这些变量。在C++中这样的代码是可以编译通过的,但是在C语言编译器中是不能编译通过的。

C编译器情况

   如果在头文件中定义static变量,在多个源文件中引入是可以编译通过的,因为相当于在每个源文件中定义了一个static变量,而static变量的作用域限定在这个源文件内的。
  如果在头文件中定义了const变量,在多个源文件中引入是不能编译通过的,因为const没有限定作用域,每个文件都定义这个变量,会出现重复定义的错误。如下:

fatal error LNK1169: one or more multiply defined symbols found


C++编译器情况

  在C++的头文件定义const或static变量,引入到多个源文件都是可以编译通过的。但是导致也导致了重复定义变量的问题。

  接下来用代码验证一下,在一个头文件中定义一个const变量,当引入到多个源文件中,查看该类的构造函数调用过几次,以及内存的变化情况。如果该头文件引入到3个文件中,那么该类的构造函数应该调用3次,内存也会明显增加。

1.头文件header.h

// header.h
#pragma once

#include <iostream>
#include <string>

struct LargeObject {
  int* p;

  LargeObject() {
    p = new int[100000000];
    std::cout << "Construct" << std::endl;
  }

  ~LargeObject() {
    delete p;
  }
};

const LargeObject kLargeObject;

const std::string kStr = "string";

2.将header.h引入到Test1.cpp中。

// Test1.h
#pragma once

void Func1();
// Test1.cpp
#include "Test1.h"
#include "Header.h"

void Func1() {
  // 输出kLargeObject 的地址。
  std::cout << "Large Object : " << &kLargeObject << std::endl;
  // 输出kStr 的地址。
  std::cout << "String: " << &kStr << std::endl;
}


3.在main.cpp中输出内存。

#include <iostream>
#include <string>
#include <windows.h>
#include <psapi.h>

#include "Test1.h"

#pragma comment(lib,"psapi.lib")

void ShowMemory() {
  HANDLE handle = GetCurrentProcess();
  PROCESS_MEMORY_COUNTERS pmc;
  GetProcessMemoryInfo(handle, &pmc, sizeof(pmc));
  std::cout << "Memory:" << pmc.WorkingSetSize / 1000 << "K"  << std::endl;
}

int main() {
  Func1();

  std::cout << std::endl;

  ShowMemory();

  return 0;
}

输出结果为:
这里写图片描述
这里写图片描述

4.将header.h引入到Test2.cpp中。

// Test2.h
#pragma once

void Func2();
// Test2.cpp
#include "Test2.h"

#include "Header.h"

void Func2() {
  // 输出kLargeObject 的地址。
  std::cout << "Large Object : " << &kLargeObject << std::endl;
  // 输出kStr 的地址。
  std::cout << "String: " << &kStr << std::endl;
}

5.在main.cpp中输出内存。

#include <iostream>
#include <string>

#include <windows.h>
#include <psapi.h>

#include "Test1.h"
#include "Test2.h"

#pragma comment(lib,"psapi.lib")

void ShowMemory() {
  HANDLE handle = GetCurrentProcess();
  PROCESS_MEMORY_COUNTERS pmc;
  GetProcessMemoryInfo(handle, &pmc, sizeof(pmc));
  std::cout << "Memory:" << pmc.WorkingSetSize / 1000 << "K"  << std::endl;
}

int main() {
  Func1();
  Func2();

  std::cout << std::endl;

  ShowMemory();

  return 0;
}

输出结果为:
这里写图片描述
这里写图片描述


结果对比

  1. 结果2的内存明显大于结果1的内存。
  2. 结果2中的构造函数调用了两次,因为该头文件引入了两次。
  3. 结果2中输出的变量地址不同,说明是不同的变量。


结论

不要直接在头文件中定义const或static变量,更好的写法是在源文件中定义,在头文件中extern声明。例如:

// defs.h
extern const std::string kStr;
extern const Student kStu;
// defs.cpp
const std::string kStr = "String";
const Student kStu("Name");
  • 21
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在QT实现多个文件共享全局变量可以通过以下两种方式: 1. 使用extern关键字 在一个文件定义全局变量,然后在其他文件使用extern关键字声明同名变量即可。这样就可以在多个文件使用同一变量。 例如,在文件A.cpp定义一个全局变量: ``` int globalVar = 0; ``` 然后在文件B.cpp使用extern关键字声明同名变量: ``` extern int globalVar; ``` 这样就可以在文件B.cpp使用globalVar变量了。 2. 使用全局变量类 QT提供了一个Q_GLOBAL_STATIC宏,可以方便地实现在多个文件共享全局变量。该宏可以将一个全局变量包装在一个类,并且该类的实例只会在第一次使用时被创建。 例如,在头文件Global.h定义一个全局变量类: ```c++ #ifndef GLOBAL_H #define GLOBAL_H #include <QtCore/QObject> #include <QtCore/QMutex> class Global : public QObject { Q_OBJECT public: explicit Global(QObject *parent = nullptr); int globalVar() const; void setGlobalVar(int value); private: QMutex mutex; int m_globalVar; }; Q_GLOBAL_STATIC(Global, globalInstance) #endif // GLOBAL_H ``` 然后在Global.cpp文件实现该类的方法: ```c++ #include "Global.h" Global::Global(QObject *parent) : QObject(parent) , m_globalVar(0) { } int Global::globalVar() const { QMutexLocker locker(&mutex); return m_globalVar; } void Global::setGlobalVar(int value) { QMutexLocker locker(&mutex); m_globalVar = value; } ``` 这样就可以在多个文件使用该全局变量了: ```c++ #include "Global.h" void foo() { globalInstance->setGlobalVar(42); } void bar() { int value = globalInstance->globalVar(); } ``` 需要注意的是,在使用Q_GLOBAL_STATIC宏时,必须将全局变量类的头文件包含在所有使用该变量的文件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值