C++17中使用inline修饰类的静态成员变量
最近在编写TDD单元测试用例时,发现在Mock一些对象的时候,有一些项目代码示例中使用inline去修饰类的静态成员变量,如:inline static std::shared_ptr<CommonUtils> utils = nullptr; ,只需要在类中声明和赋值,没有在类外去赋值,这种用法之前没见过,于是开始网上查资料,稍微研究了一下。
C++中在类中定义了一个静态变量:inline static std::shared_ptr utils = nullptr; 这个用法C++11支持么?一般是怎么使用的,使用场景和用途、好处是什么?如果C++11不支持,一般怎么修改?
使用inline static修饰类的静态成员变量的C++代码示例inlineStaticMemDemo.cpp如下:
cpp
#include <memory>
#include <iostream>
class CommonUtils {
public:
CommonUtils() {
std::cout << "CommonUtils Constructor" << std::endl;
}
~CommonUtils() {
std::cout << "CommonUtils Destructor" << std::endl;
}
};
class MyClass {
public:
// 在类内部声明和定义静态成员变量
inline static std::shared_ptr<CommonUtils> utils = nullptr;
// 静态方法初始化静态成员变量
static void initializeUtils() {
if (!utils) {
utils = std::make_shared<CommonUtils>();
}
}
};
int main() {
// 初始化静态成员变量
MyClass::initializeUtils();
// 使用静态成员变量
if (MyClass::utils) {
std::cout << "Static shared_ptr is initialized and ready to use." << std::endl;
}
return 0;
}
在我的MacOS mini4系统上使用Apple clang version 17.0.0 (clang-1700.0.13.5)编译器,编译命令为:
bash
g++ inlineStaticMemDemo.cpp -o inlineStaticMemDemo
编译结果如下:
bash
192:StaticMemberExample john$ g++ inlineStaticMemDemo.cpp -o inlineStaticMemDemo
inlineStaticMemDemo.cpp:17:5: warning: inline variables are a C++17 extension [-Wc++17-extensions]
17 | inline static std::shared_ptr<CommonUtils> utils = nullptr;
| ^
1 warning generated.
可以看到上述编译告警中说了inline修饰类的static静态成员变量是C++17扩展,C++17及以后的编译器才支持。
如果我们改用如下命令,在原来编译命令的基础上加上-std=c++17 编译参数呢?看一下编译和运行结果,运行结果如下:
bash
192:StaticMemberExample john$ g++ inlineStaticMemDemo.cpp -o inlineStaticMemDemo -std=c++17
192:StaticMemberExample john$ ./inlineStaticMemDemo
CommonUtils Constructor
Static shared_ptr is initialized and ready to use.
CommonUtils Destructor
可以看出在原来编译命令的基础上加上-std=c++17 编译参数,就不会出现告警信息了,侧面说明使用inline修饰类的静态成员变量是从C++17开始支持的。
1. inline static 的支持情况
inline static 是 C++17 引入的新特性,C++11 不支持 inline static。在 C++11 中,静态成员变量需要在类外部进行定义和初始化,而不能直接在类内初始化。
2. 使用场景和用途
使用场景
- 单例模式 :
inline static可以用来实现单例模式,确保类的某个静态成员变量在所有实例中共享。 - 共享资源 : 当多个对象需要共享某些公共资源时,可以使用
inline static定义一个静态成员变量。 - 减少全局变量 : 使用
inline static可以将全局变量的作用域限制在类内部,避免全局变量污染命名空间。
用途和好处
- 简化代码: 在类内直接初始化静态成员变量,无需在类外部重复定义。
- 提高可读性: 将变量的定义和初始化放在类内,代码更清晰。
- 减少链接错误 : 传统的静态变量需要在类外部定义,容易导致链接错误,而
inline static避免了这种问题。
3. 如果 C++11 不支持,如何修改?
在 C++11 中,不能在类内直接初始化静态成员变量。需要在类外部定义和初始化静态成员变量。
修改后的代码
cpp
#include <memory>
#include <iostream>
class CommonUtils {
public:
CommonUtils() {
std::cout << "CommonUtils Constructor" << std::endl;
}
~CommonUtils() {
std::cout << "CommonUtils Destructor" << std::endl;
}
};
class MyClass {
public:
// 声明静态成员变量
static std::shared_ptr<CommonUtils> utils;
// 静态方法初始化静态成员变量
static void initializeUtils() {
if (!utils) {
utils = std::make_shared<CommonUtils>();
}
}
};
// 在类外部定义静态成员变量
std::shared_ptr<CommonUtils> MyClass::utils = nullptr;
int main() {
// 初始化静态成员变量
MyClass::initializeUtils();
// 使用静态成员变量
if (MyClass::utils) {
std::cout << "Static shared_ptr is initialized and ready to use." << std::endl;
}
return 0;
}
4. 使用场景和用途
使用场景
- 单例模式: 静态变量可以用来实现单例模式,确保某个类的实例在整个程序中只有一个。
- 共享资源 : 静态变量可以在类的所有实例之间共享数据。例如,
std::shared_ptr可以用来管理共享资源的生命周期。 - 延迟初始化: 静态变量可以通过延迟初始化的方式,避免在程序启动时就占用资源。
用途和好处
- 资源共享: 静态变量允许多个对象共享同一个资源,避免重复创建。
- 延迟初始化: 通过延迟初始化,可以在需要时才分配资源,减少程序启动时的开销。
- 自动内存管理 : 使用
std::shared_ptr可以自动管理资源的生命周期,避免手动释放内存。
5. C++11 和 C++17 的对比
| 特性 | C++11 | C++17 |
|---|---|---|
| 静态变量初始化 | 必须在类外部定义并初始化 | 可以在类内使用 inline static 初始化 |
| 代码简洁性 | 需要额外的类外定义,代码较冗长 | 类内直接初始化,代码更简洁 |
| 链接错误的可能性 | 类外定义时,容易因遗漏定义导致链接错误 | 避免了链接错误 |
| 支持的编译器 | 支持 C++11 的编译器 | 需要支持 C++17 的编译器 |
6. 总结
- C++11 不支持
inline static,需要在类外部定义和初始化静态成员变量。 - 使用场景: 适用于单例模式、共享资源管理等场景。
- 好处: 提高代码可读性,减少全局变量,简化资源管理。
- C++17 的改进 : 使用
inline static可以直接在类内初始化静态成员变量,避免类外定义的麻烦。
如果你的项目需要兼容 C++11,可以按照上述代码进行修改。如果可以升级到 C++17,则可以直接使用 inline static,代码会更加简洁。