C++17中使用inline修饰类的静态成员变量

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,代码会更加简洁。

相关推荐
星火开发设计2 小时前
共用体 union:节省内存的特殊数据类型
java·开发语言·数据库·c++·算法·内存
仰望星空_Star2 小时前
Java证书操作
java·开发语言
女王大人万岁2 小时前
Go语言time库核心用法与实战避坑
服务器·开发语言·后端·golang
云游云记2 小时前
php Token 主流实现方案详解
开发语言·php·token
m0_748229992 小时前
Laravel5.x核心特性全解析
开发语言·php
河北小博博2 小时前
分布式系统稳定性基石:熔断与限流的深度解析(附Python实战)
java·开发语言·python
岳轩子2 小时前
JVM Java 类加载机制与 ClassLoader 核心知识全总结 第二节
java·开发语言·jvm
智航GIS2 小时前
ArcGIS Python零基础脚本开发教程---1.1 Describe 函数
开发语言·python·arcgis
云游云记2 小时前
php 网络请求工具全解:cURL 与 Guzzle 总结
开发语言·网络·php