C++的存储区分为五种:自动存储区;寄存器存储区;静态存储区;动态存储区;线程存储区
1.自动存储区(auto storage class)
指在函数内部定义的变量.当函数被调用时,这些变量被分配在栈内存中,并随之函数的执行而创建和销毁
自动存储区中的变量具有默认的初始值,如果在定义时没有显式地初始化,其值将不确定
自动存储区中的变量有以下几个特点:
- 变量的作用域仅限于函数内部
- 变量的生命周期随着函数的结束而结束
- 变量的值不会被跨函数保存,即使变量的地址被返回,返回的也是栈地址,该地址在函数执行结束后就无效了
- 变量的存储空间有限,因为它们在栈中分配,当栈的空间不足,可能导致栈溢出
通过在自动存储区中的变量,可以方便的在函数内部保存临时变量,而不需额外分配内存空间,同时,由于变量的生命周期具有明确的结束条件,在程序中也不不容易出现内存泄漏的情况
2.寄存存储区
C++中的寄存器存储区是指使用register关键字声明的变量。这些变量会被存储在CPU的寄存器中,而不是存储在内存中。由于寄存器的读写速度通常比内存更快,因此使用寄存器存储区的变量可以提高程序的执行速度。
使用寄存器存储区需要注意以下几点:
- 寄存器存储区的总空间非常有限,通常只有几个寄存器,因此只有频繁使用的变量才能被声明为寄存器变量;
- 使用寄存器存储区的变量不能取地址,因为在寄存器中存储的是变量的值,而不是变量的地址;
- 编译器可以选择忽略寄存器关键字,这是因为一个变量在寄存器中并不一定比在内存中更快;
- 使用寄存器存储区的变量具有与自动存储区的变量相同的作用域和生命周期。
虽然使用寄存器存储区可以提高程序的执行效率,但是对于大多数应用程序来说,优化的效果非常有限,因为现代CPU的流水线执行方式已经非常高效。因此,在实际编程中,使用寄存器存储区应该谨慎,只有在必要的情况下才使用。
3.静态存储区
指函数外部定义的静态变量、全局变量以及静态成员变量
这些变量会在程序启动时被分配到静态存储区中,并在程序执行期间一直存在,直到程序运行结束才被销毁,静态存储区位于程序的数据段
静态存储区的变量特点:
- 变量的作用域为文件作用域或者全局作用域
- 声明周期和程序的生命周期相同
- 变量的值在程序运行期间保持不变(对于未初始化的变量,其值为0或者空指针)
- 变量在程序启动时被初始化,如果没有明确的指定初始化值,则默认为0或者空指针
- 静态存储区的空间是有限的,因此要避免过多的使用全局变量和静态变量,以免造成内存的浪费
4.动态存储区
动态存储区是指在程序运行的过程中使用new运算符或者malloc函数动态的分配内存空间.动态存储区是从堆区中取得一块内存空间,其大小和位置由程序员在运行时控制
动态存储区特点:
- 动态存储区在程序运行时分配内存,它的生命周期由程序员控制,分配的内存空间可以在不需要的时候手动释放
- 动态存储区可以根据需要动态的分配和释放内存,因此非常灵活,可以用于存储数据结构或者动态的增长数组等数据
- 动态存储区的空间相对较大,但是需要指向内存管理操作,若内存管理不当,容易出现内存泄漏或内存溢出等问题
在使用动态存储区时,必须要注意一些问题,包括:
- 及时释放内存空间,避免内存泄漏;
- 避免越界访问数组,避免内存溢出;
- 对于已经释放的内存空间,不要再次使用,防止野指针的出现;
- 适当地使用智能指针等工具来帮助管理内存空间,以避免手动管理内存带来的复杂性和风险。
动态存储区为程序员提供了极大的灵活性和控制性,可以有效地提高程序的运行效率,但使用不当也会带来诸多隐患。因此,在编写 C++ 程序时,尽可能使用静态存储区和自动存储区,必要时再使用动态存储区,以确保程序的正确性和稳定性。
5.线程存储区
C++的线程存储区是指在多线程环境下,为每个线程单独分配的变量内存。C++标准中引入了`thread_local`关键字,用于定义线程局部变量(Thread-local storage, TLS)。线程局部变量是指不同线程之间相互独立的变量。
在使用`thread_local`定义变量时,每个线程都会独立获得一份变量的副本,这些副本会在该线程结束时被销毁。这样,不同线程之间就不会相互影响,也不需要使用锁等同步机制来保护这些变量的访问。
例如:
#include <iostream>
#include <thread>
thread_local int i = 0;
void threadFunction() {
i++;
std::cout << "Thread " << std::this_thread::get_id() << ": i = " << i << std::endl;
}
int main() {
std::thread t1(threadFunction);
std::thread t2(threadFunction);
t1.join();
t2.join();
return 0;
}
在上面的代码中,我们使用`thread_local`关键字定义了一个名为`i`的变量,并在两个线程(`t1`和`t2`)中调用了`threadFunction`函数。在每个线程中,变量`i`的值都会被自增,并输出到控制台上,可以看到输出结果:
Thread 1: i = 1
Thread 2: i = 1
可以看到,对于不同的线程,变量`i`的值都是独立的,不会相互干扰。这就是线程局部变量的作用。