1.C++学习笔记:内存模型

本文详细解析了C++中的变量存储特性,包括自动存储持续性、静态存储持续性和动态存储持续性的概念及其应用场景。同时介绍了作用域的概念及链接性的基本原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++学习笔记

存储持续性、作用域和链接性

C++和C语言对于变量定义的方式类型,定义的不同方式确定了变量的生存周期、作用范围以及可以被谁使用的“权限”问题。

存储持续性

一般来讲我们把存储的持续性简称为变量在程序中定义的位置,有以下三个位置:

1.自动存储持续性:简称自动变量,该变量定义在具体的函数块中,并且不加(static)这种修饰符,该类变量从函数被调用时代码块创建开始到函数执行结束时被释放。

2.静态存储持续性:在函数块外定义的变量(全局变量)和使用关键字static定义的变量的存储特性都是静态的,该类变量在程序的整个生命周期都存在。

3.动态存储持续性:这类内存一般是使用malloc或new申请,通过free或delete进行释放。需要程序员自己进行内存的管理。

如下面这个例子:

//存储数据的三种方案

#include <iostream>

using namespace std;

int global_value = 1;    //静态存储持续性

void func1(void);

void func1(void)
{
    int func1_auto_value = 0;    //自动存储持续性
    static int func1_static_value = 0;    //静态存储持续性
}

int main(int argc, char **argv)
{
    int auto_value = 0;   //自动存储持续性
    int *p_value = NULL;
    func1();

    // p_value为自动存储持续性,而p_value所申请的内存为动态存储持续性
    p_value = (int *)malloc(sizeof(int) * 100);
    if(p_value == NULL){
        cout << "the memory is full!" << endl;
        exit(1);
    }

    free(p_value);    //p_value所申请的内存需要及时释放
    return 0;
}

作用域

关于作用于只要记住以下几点即可:

这里写图片描述

链接性

关于链接性建议大家可以阅读一本较为底层的书《程序员的自我修养》,其中的部分章节详细的介绍了静态链接、动态链接以及符号相关的知识。
如果是linux或unix操作系统建议大家熟练掌握,objdumpredelf这两个可以查看汇编以及底层链接属性的命令,对于寄存器级别的调试非常有用。

说明符和限定符

在C++中我们还需要注意存储说明符和cv限定符。这里和C语言有着少许差异和扩充。

说明符

说明符包含以下几个:

auto (修饰自动类型变量)
register (用于声明中尽量把变量放置在寄存器中)
static (表示内部链接性,修饰的变量不再是全局符号
extern (引用外部的定义变量或者函数)
thread_local(C++11新增)
mutable

其中需要着重解释下thread_localmutable

thread_local相当于把修饰的变量当做是线程内部的一部分。

//thread_local test

thread_local int value = 1;

void func1(void);

void func1(void)
{
    m.lock();
    value++;    //value编程了每个线程内部的变量,各个线程的value不会共享
    m.unlock();
}

int main(int argc, char **argv)
{
    std::thread t1(func1);
    std::thread t2(func1);
    t1.join();
    t2.join();
    // value is 1
    return 0;
}

mutable的用来指定即使结构体或者类变量被定义为const,但是被mutable修饰的变量依然可以修改。

// mutable test

struct Test
{
    int a;
    mutable int b;
};

int main(int argc, char **argv)
{
    const Test test1 = {12, 20};
    test1.a = 20;    //false
    test1.b = 30;    // true

    return 0;
}
cv-限定符

const (常性)
volatile (去掉编译器的优化)

const修饰的变量在定义之后不可以被修改(实际上这句话是有缺陷的)。

//const修饰的变量不能被修改的探讨

int main(int argc, char **argv)
{
    const int value = 10;
    value = 30;   //false
    int *p_int = (int *)&value;
    *p_int = 30;   //true
}

也就是说被修饰的value当然不能直接更改,但是如果有int *指针指向了他,使用指针去间接修改value,这种漏洞编译器是很难察觉的,但是作为程序员我们不能去欺负编译器的粗心!!!

volatile的存在是因为在程序中如果发现某个值被多次赋值,则编译器会进行优化,不再每次都从内存取值,而是把该值放在了寄存器中,如果是单线程程序当然这是一个比较好的优化,但是对于多线程程序来说,在多次赋值的期间该变量有可能被其他线程已经修改,这样就会造成错误赋值的过程。为了避免这种过度的优化,我们使用了volatile关键字,这样就会提示编译器每次都去内存中取值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值