C++ 存储类
C++ 中的存储类和说明符
Section titled “C++ 中的存储类和说明符”C++ 中的存储类说明符(storage class specifiers)定义了变量和函数的生命期(duration)和链接性(linkage,即在翻译单元之间的可见性)。它们位于所修饰类型之前。主要的存储类说明符有:
auto(自 C++11 起:用于类型推断,而非存储类)register(已弃用)staticexternmutablethread_local(自 C++11 起)
auto 关键字(C++11 及更高版本)
Section titled “auto 关键字(C++11 及更高版本)”在现代 C++(C++11 及更高版本)中,auto 不是存储类说明符。相反,它用于自动类型推断(automatic type deduction)。编译器根据变量的初始化表达式推断其类型。未与其它说明符一起声明为 auto 的变量默认具有自动存储期(automatic storage duration)(就像局部变量一样)。
// C++11 及更高版本#include <vector>
int main() { auto count = 10; // count 被推断为 int auto pi = 3.14159; // pi 被推断为 double auto message = "Hello"; // message 被推断为 const char*
std::vector<int> numbers = {1, 2, 3}; auto it = numbers.begin(); // it 被推断为 std::vector<int>::iterator
// auto 可以与 const, &, &&, * 结合使用 const auto MAX_SIZE = 100; // const int auto& ref_count = count; // int&}auto 简化了代码,尤其在使用迭代器或 lambda 表达式等复杂类型时。auto 的原始含义(显式声明自动存储期)已经过时。
register 关键字(已弃用)
Section titled “register 关键字(已弃用)”register 关键字在历史上是向编译器发出的一个提示,建议将变量存储在 CPU 寄存器中以加快访问速度。然而,现代编译器在优化和寄存器分配方面表现出色,这使得该关键字在很大程度上已过时且无效。它在 C++17 中被弃用(deprecated),强烈不建议使用。编译器通常会忽略它。
// 避免使用 'register'// register int counter; // 现代编译器会忽略此提示请依赖编译器优化,而不是使用 register。
static 说明符
Section titled “static 说明符”static 关键字根据上下文具有不同的含义:
- 在函数/块内部(静态局部变量): 变量在函数调用或块进入之间保留其值。它只初始化一次(自 C++11 起线程安全初始化)。它具有静态存储期(static storage duration),但具有块作用域(block scope)。
- 在命名空间作用域(全局变量/函数): 它赋予变量或函数内部链接性(internal linkage)。这意味着它只在当前的翻译单元(定义它的
.cpp文件)内可见。这有助于避免文件之间的命名冲突。 - 在类定义内部(静态类成员): 创建一个属于类本身而非任何特定对象实例的成员变量或函数。类的所有对象共享相同的静态成员变量。静态成员函数可以使用类名调用(
ClassName::staticFunc();),并且只能访问其他静态成员。
演示静态局部变量和全局变量的示例:
#include <iostream>
// 静态全局变量(内部链接性)// 仅在此文件 (cpp_storage_classes.cpp) 内可见static int file_scope_count = 10;
// 函数声明void func();
int main() { while (file_scope_count > 0) { func(); file_scope_count--; // 修改文件作用域变量 } return 0;}
// 函数定义void func() { // 静态局部变量 // 只初始化一次,在函数调用之间保留值 static int i = 5; i++; std::cout << "i is " << i; std::cout << " and file_scope_count is " << file_scope_count << std::endl;}编译并执行后,将产生以下输出:
i is 6 and file_scope_count is 10i is 7 and file_scope_count is 9i is 8 and file_scope_count is 8i is 9 and file_scope_count is 7i is 10 and file_scope_count is 6i is 11 and file_scope_count is 5i is 12 and file_scope_count is 4i is 13 and file_scope_count is 3i is 14 and file_scope_count is 2i is 15 and file_scope_count is 1extern 说明符
Section titled “extern 说明符”extern 关键字用于声明在另一个翻译单元(translation unit,另一个 .cpp 文件)或同一文件稍后位置定义的变量或函数。它主要影响链接性(linkage)。
- 对于变量: 它声明一个变量但不定义它(不分配内存)。它告诉编译器,存在一个同名同类型的变量在其他地方(通常在另一个
.cpp文件中)定义,并且具有外部链接性(external linkage,这是未声明为static的全局变量的默认链接性)。你不能在extern声明中初始化变量。 - 对于函数: 声明函数为
extern通常是冗余的,因为函数默认具有外部链接性,除非声明为static。有时为了清晰起见会使用它。 - 链接性规范:
extern "C"用于声明应使用 C 链接约定(C linkage conventions)的函数,允许 C++ 代码与 C 库交互。
使用两个文件共享全局变量的示例:
文件 1: main.cpp
#include <iostream>
// 声明在其他地方定义的 'shared_counter'extern int shared_counter;
// 声明在其他地方定义的函数extern void print_counter();
int main() { shared_counter = 5; // 修改共享变量 std::cout << "main.cpp: Set shared_counter to " << shared_counter << std::endl; print_counter(); // 调用另一个文件中的函数 return 0;}文件 2: support.cpp
#include <iostream>
// 全局变量的定义(默认外部链接性)int shared_counter = 0; // 在这里进行初始化
// 函数定义void print_counter() { std::cout << "support.cpp: shared_counter is " << shared_counter << std::endl;}编译并链接这些文件(使用 g++ 的示例):
g++ main.cpp support.cpp -o shared_var_example -std=c++11运行 ./shared_var_example 将产生:
main.cpp: Set shared_counter to 5support.cpp: shared_counter is 5mutable 说明符
Section titled “mutable 说明符”mutable 说明符仅适用于类的非静态、非常量数据成员。它允许即使对象被声明为 const,或者通过 const 成员函数访问时,也能修改该成员变量。这通常用于不影响对象可观察状态(observable state)的内部状态,例如缓存或互斥锁(mutexes)。
class Example { mutable int cache_value; // 可以被 const 方法修改 int regular_value; mutable bool cache_valid = false; // 将其也设为 mutablepublic: Example(int val) : regular_value(val) {}
int getValue() const { // 这是一个 const 成员函数 if (!cache_valid) { // 模拟耗时计算 cache_value = regular_value * 2; // OK: cache_value 是 mutable 的 cache_valid = true; // OK: cache_valid 是 mutable 的 } // regular_value = 10; // 错误:不能在 const 函数中修改非 mutable 成员 return cache_value; }};thread_local 说明符 (C++11)
Section titled “thread_local 说明符 (C++11)”thread_local 说明符声明一个变量具有线程存储期(thread storage duration)。这意味着程序中的每个线程都将拥有该变量自己的独立实例。它对于线程特定数据(thread-specific data)非常有用,例如每线程的错误码或随机数生成器。
#include <iostream>#include <thread>#include <vector>
// 每个线程都有自己的 thread_id 副本thread_local int thread_specific_id = 0;int global_id_counter = 0; // 共享计数器
void worker_thread(int id) { thread_specific_id = id; // 设置此线程的 ID global_id_counter++; std::cout << "Thread " << std::this_thread::get_id() << ": thread_specific_id = " << thread_specific_id << ", global_id_counter = " << global_id_counter << std::endl;}
int main() { std::vector<std::thread> threads; for (int i = 1; i <= 3; ++i) { threads.emplace_back(worker_thread, i * 100); }
for (auto& t : threads) { t.join(); }
std::cout << "Main thread: thread_specific_id = " << thread_specific_id << ", global_id_counter = " << global_id_counter << std::endl; return 0;}输出可能显示不同的 thread_specific_id 值,但 global_id_counter 会递增,这表明每个线程都有其自己的 thread_specific_id。