前言

这一节我们将学习修饰符类型的的相关知识,可能会涉及到一些C++的基本语法以及C++变量类型、C++变量作用域的相关知识,如果你还有不明白的,请到C++基本语法C++变量类型C++变量作用域这里温故一下

C++存储类型


什么是存储类?

存储类决定了变量或函数的作用范围(在哪里可以访问)和生命周期(何时创建、何时销毁)。在C++中,存储类的关键字会放在变量或函数类型的前面,用来改变它们的默认行为。


C++中常见的存储类说明符

以下是C++存储类关键字的通俗解释:

1. auto(自动存储期,默认行为)

  • 定义:这是C++的默认存储类说明符,通常可以省略不写。它表示变量的生命周期仅限于它所在的块(如函数内部)。
  • 特点
    • 变量会在块结束时自动销毁。
    • 在C++11后,auto更多用于自动推导变量类型,而不是存储类。
  • 示例
    1
    2
    3
    void function() {
    auto int x = 10; // x 是局部变量,块结束后自动销毁
    }

2. register(寄存器变量)

  • 定义:建议编译器将变量存储在CPU寄存器中以提高访问速度。
  • 特点
    • 在现代C++中(C++11及以后),register已经被废弃,编译器会自动优化变量的存储。
    • 示例
      1
      2
      3
      void function(register int x) {
      // x 是建议存储在寄存器中的变量
      }

3. static(静态存储期)

  • 定义:表示变量的生命周期贯穿整个程序的运行期。
  • 特点
    • 函数内部的static变量:只初始化一次,函数多次调用时会保留上次的值。
    • 全局变量或函数的static:限制变量或函数只能在当前文件中使用。
  • 示例
    1
    2
    3
    4
    5
    void function() {
    static int count = 0; // count 只初始化一次
    count++;
    std::cout << count; // 多次调用会保留上次的值
    }

4. extern(外部链接)

  • 定义:声明全局变量或函数,可以跨多个文件使用。
  • 特点
    • extern告诉编译器变量或函数是在别的文件中定义的。
    • 示例
      文件1:file1.cpp
      1
      int globalVar = 10; // 定义全局变量
      文件2:file2.cpp
      1
      extern int globalVar; // 引用 file1.cpp 中的变量

5. mutable(可变成员变量)

  • 定义:修饰类的成员变量,即使类对象是const,也允许修改这个变量。
  • 特点
    • 通常用于需要在const成员函数中更新的变量,比如缓存或计数器。
    • 示例
      1
      2
      3
      4
      5
      6
      7
      8
      class Example {
      public:
      mutable int counter; // counter 可以在 const 函数中修改

      void increment() const {
      counter++; // 合法
      }
      };

6. thread_local(线程局部存储期,C++11 引入)

  • 定义:表示每个线程都有变量的独立副本,变量的生命周期与线程一致。
  • 特点
    • 适合多线程编程中需要每个线程独立数据的场景。
    • 示例
      1
      thread_local int threadVar = 0; // 每个线程都有自己的 threadVar

示例总结

以下代码展示了不同存储类的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

int globalVar; // 全局变量,默认是 extern

void function() {
auto int localVar = 10; // 局部变量,块结束后销毁
static int staticVar = 20; // 静态变量,函数多次调用保留值
thread_local int threadVar = 30; // 每个线程有独立的变量副本

class MyClass {
public:
mutable int mutableVar; // 可变变量,即使对象是 const 也可以修改
void modify() const {
mutableVar = 50; // 合法
}
};
}

小总结

关键字 特点
auto 默认存储类,生命周期随块结束,现代C++更多用于类型推导。
register 提示编译器优化变量存储(C++11后废弃)。
static 生命周期贯穿整个程序,但作用范围受限。
extern 允许跨文件共享全局变量或函数。
mutable 允许修改const对象的成员变量。
thread_local 每个线程有独立变量副本,生命周期与线程一致(C++11后引入)。

常见存储类及其用途

1. auto(自动推导类型)

  • 定义:自动根据初始化的值推断变量的类型。
  • 特点
    • 省去了手动写类型的麻烦。
    • 适合用在复杂类型的变量上,比如迭代器。
  • 示例
    1
    2
    3
    auto a = 10;     // 推断为 int
    auto b = 3.14; // 推断为 double
    auto c = "hello"; // 推断为 const char*

2. register(寄存器变量,C++11后已废弃)

  • 定义:建议将变量存储在CPU寄存器中,以便快速访问。
  • 特点
    • 提高访问速度,适合频繁使用的变量。
    • 在现代编译器中,register的效果已被优化算法替代。
  • 示例
    1
    register int i = 0; // 提示编译器将 i 存储在寄存器中

3. static(静态变量)

  • 定义:变量的生命周期贯穿程序始终,无论它在局部还是全局作用域。
  • 特点
    • 局部静态变量:函数内部的static变量只初始化一次,值会在函数调用之间保留。
    • 全局静态变量:只能在当前文件中使用,其他文件无法访问。
    • 类静态变量:类中所有对象共享一个静态变量。
  • 示例
    1
    2
    3
    4
    5
    void counter() {
    static int count = 0; // 只初始化一次
    count++;
    std::cout << count << std::endl;
    }

4. extern(外部变量)

  • 定义:声明一个全局变量或函数,使其在多个文件之间共享。
  • 特点
    • 通常用于跨文件访问变量或函数。
    • 示例
      文件1:file1.cpp
      1
      int sharedVar = 42; // 定义全局变量
      文件2:file2.cpp
      1
      2
      extern int sharedVar; // 引用 file1 中的变量
      std::cout << sharedVar;

5. mutable(可变成员变量)

  • 定义:修饰类的成员变量,即使类对象是const,这个变量也可以被修改。
  • 特点
    • 通常用于缓存、计数器等需要在const上下文中改变状态的场景。
  • 示例
    1
    2
    3
    4
    5
    6
    7
    class Example {
    mutable int counter; // 可变变量
    public:
    void increment() const {
    counter++; // 合法
    }
    };

6. thread_local(线程本地存储,C++11引入)

  • 定义:每个线程都有一个独立的变量副本,线程之间互不干扰。
  • 特点
    • 适用于多线程编程。
    • 每个线程的thread_local变量在线程结束时销毁。
  • 示例
    1
    2
    3
    4
    5
    thread_local int threadVar = 0;

    void threadFunc(int id) {
    threadVar = id; // 每个线程有独立的变量
    }

使用场景总结

存储类 适用场景
auto 自动推断变量类型,简化复杂类型的声明。
register 提示频繁使用的变量(现代C++中已废弃)。
static 保留局部变量值、限制全局变量访问范围、类成员共享变量。
extern 跨文件共享全局变量和函数。
mutable const对象中允许修改成员变量(如缓存或计数器)。
thread_local 线程安全,每个线程都有独立的变量副本。