[modern c++] 如何在h/hpp头文件中定义一个常量,并限制其不被没有include本头文件的编译单元访问到

前言:

定义一个在编译时就可以获得常量是很有用的,比如如果希望定义一个一定容量的raw数组,那么就需要指定数组的尺寸,这个时候就有很多种方法来实现,比如 #define 宏 ,constexpr,在源文件中定义变量等等。

方法:

1. 使用 #define 宏

最常用,也是最简单的方法就是使用 #define 定义一个宏,这样做的缺点是一旦被定义成宏,那么这个值就是全局可知的,因此无法约束其访问范围。

cpp 复制代码
#define ARR_SIZE 1024

2. c++中,使用匿名namespace 在源文件中定义

c++98 提出了匿名namesapce ,所有定义在匿名namespace中的变量都具备内部连接属性,所以可以把续要定义的值放在匿名namespace里,再把相关代码放入源文件里,这样做的缺点在于无法在h/hpp头文件中访问到这些变量,因此头文件无法获知源文件里的值。

cpp 复制代码
//1.hpp
extern constexpr int ARR_SIZE; //错误
int arr[ARR_SIZE]; //由于无法访问cpp中的符号,所以这里没法定义arr的尺寸。


//1.cpp
#include "1.hpp"
constexpr int ARR_SIZE = 100;

3. c++中,使用匿名namespace 在头文件中定义

和2不同的是,把所有定义放到头文件里,这样做虽然解决了头文件中获知相关值的目的,但是引入了ODR 问题,所有include当前头文件的源文件都将包含一套匿名namespace中的所有值,而这些值会有N个副本,而不是共享同一个副本。

cpp 复制代码
//1.hpp
namespace{
  constexpr int ARR_SIZE = 100;
};


//2.cpp
#include "1.hpp"    //2.cpp中 有一个ARR_SIZE 副本
static int arr[ARR_SIZE];   


//3.cpp
#include "1.hpp"    //3.cpp中 有一个ARR_SIZE 副本
static int arr[ARR_SIZE];

4. c++中,使用inline来保证实例的单一性

3中已经通过匿名namespace保证了ARR_SIZE不会被没有 #include "1.hpp" 的源文件访问到,但是苦于其引入了 ODR 问题,所以不是 100% 正确的实现,也就是说功能性能够满足,但是引入了其他问题。

100%正确的写法其实是使用 inline 在头文件中定义这样一个常量表达式。

cpp 复制代码
//1.hpp
inline constexpr int ARR_SIZE = 100;
int arr[ARR_SIZE];

//1.cpp
#include "1.hpp"
std::cout << ARR_SIZE << std::endl;   //可以通过include头文件的方式在 源文件中访问

//2.cpp
#include "1.hpp"
std::cout << ARR_SIZE << std::endl;   //可以通过include头文件的方式在 源文件中访问

/* 虽然 1.cpp 和 2.cpp 都使用了 ARR_SIZE , 但是由于头文件中使用了 inline 进行修饰,因此能够保证 ARR_SIZE 具备全局唯一性,即1.cpp 和 2.cpp中访问的是同一个实例ARR_SIZE */
相关推荐
写代码的小王吧22 分钟前
【Java可执行命令】(十)JAR文件签名工具 jarsigner:通过数字签名及验证保证代码信任与安全,深入解析 Java的 jarsigner命令~
java·开发语言·网络·安全·web安全·网络安全·jar
小卡皮巴拉29 分钟前
【力扣刷题实战】矩阵区域和
开发语言·c++·算法·leetcode·前缀和·矩阵
努力搬砖的咸鱼40 分钟前
Qt中的数据解析--XML与JSON处理全攻略
xml·开发语言·qt·json
Pacify_The_North42 分钟前
【C++进阶三】vector深度剖析(迭代器失效和深浅拷贝)
开发语言·c++·windows·visualstudio
神里流~霜灭1 小时前
蓝桥备赛指南(12)· 省赛(构造or枚举)
c语言·数据结构·c++·算法·枚举·蓝桥·构造
一人の梅雨1 小时前
化工网平台API接口开发实战:从接入到数据解析‌
java·开发语言·数据库
扫地的小何尚1 小时前
NVIDIA工业设施数字孪生中的机器人模拟
android·java·c++·链表·语言模型·机器人·gpu
Zfox_1 小时前
【C++项目】从零实现RPC框架「四」:业务层实现与项目使用
linux·开发语言·c++·rpc·项目
我想吃余1 小时前
【C++篇】类与对象(上篇):从面向过程到面向对象的跨越
开发语言·c++
Niuguangshuo1 小时前
Python设计模式:克隆模式
java·开发语言·python