C++内存布局以及常用关键字

C++内存布局以及常用关键字

C++的内存空间

代码存储区域:常量区、代码区、静态区(全局区)、堆区、栈区

栈区向下增长,堆区向上增长。栈由系统管理,没有内存碎片,每个元素之间都是连续的,大小比较小,8k,可以修改系统参数,堆区存储动态开辟的变量。

还有一个内核空间,但是它不与用户直接交互(内核区)。

C++的内存空间

常用关键字

static

修饰局部变量:局部变量的存储区域改变、变为静态区,生命周期改为程序结束才销毁。

修饰全局变量:全局变量只能在本文件中访问,不能在其它文件中访问, extern 外部声明也不可以。

修饰成员变量:静态成员变量不属于实体的类对象,要在类外初始化

修饰成员函数:静态函数属于类不属于类对象 需要通过类作用域调用 函数无this指针(静态成员函数仅能访问静态的数据成员,不能访问非静态的数据成员,也不能访问非静态的成员函数)

#define

带参数的宏定义可以减少函数调用的开销,在运行时只是简单的展开。

#include <iostream>
#define SQUARE(x) ((x) * (x))int main() {int a = 5;std::cout << "Square of a: " << SQUARE(a) << std::endl;std::cout << "Square of a+1: " << SQUARE(a + 1) << std::endl;return 0;
}

代码会被展开为:

std::cout << "Square of a: " << ((a) * (a)) << std::endl;
std::cout << "Square of a+1: " << ((a + 1) * (a + 1)) << std::endl;

同样逻辑使用函数实现:

inline int square(int x) {return x * x;
}

虽然 inline 函数也可能避免函数调用开销,但其行为是在编译阶段由编译器决定;而宏定义是在预处理阶段直接展开。因此,宏展开比函数调用更加简单直接。

const

申明一个常量,在编译期间可以进行类型检查,确保其值在程序运行期间不能被修改。

它还可以应用于指针、函数形参和成员函数等不同场景。

基本用法示例

  1. 定义常量

    const int a = 10; // 定义一个整型常量
    a = 20;           // 错误,尝试修改常量的值
    

    在编译阶段,如果试图修改 a 的值,会报错:
    “assignment of read-only variable ‘a’”

  2. 指针中的 constconst 在指针上下文中非常灵活,具体含义取决于其位置(需要注意理解哦:

    • 指针指向的值不可变

      const int* ptr = &a; // 指针指向的内容是只读的
      *ptr = 20;           // 错误
      ptr = &b;            // 正确,可以修改指针本身
      
    • 指针本身不可变

      int* const ptr = &a; // 指针本身是常量,不能指向其他地址
      *ptr = 20;           // 正确
      ptr = &b;            // 错误
      
    • 值和指针均不可变

      const int* const ptr = &a; // 值和指针都不可更改
      *ptr = 20;                // 错误
      ptr = &b;                 // 错误
      
  3. 函数参数中的 const

    • 传值参数: 如果函数参数是按值传递,const 修饰没有意义,因为传入的值本身就是副本,修改不会影响原始变量。

    • 传引用参数: 使用 const 修饰引用,可以保护原始数据:

      void print(const std::string& str) {// str 是只读的std::cout << str << std::endl;
      }
      

      好处:

      • 避免拷贝,提高性能。
      • 防止函数内部修改传入的数据。
  4. 成员函数中的 const: 当一个成员函数后面添加 const 修饰符时,表示该函数不会修改对象的任何成员变量

    class MyClass {
    private:int value;
    public:int getValue() const {return value; // 只读操作}
    };
    

    如果尝试在 const 成员函数中修改任何非 mutable 的成员变量,编译会报错。

  5. const 和数组: 声明只读的数组:

    const int arr[] = {1, 2, 3}; // 数组的内容是只读的
    arr[0] = 10;                 // 错误
    

mutable

mutable为可变的,易变的跟C++中的const是反义词。被mutable修饰的变量(mutable智能用于修饰类的非静态数据成员),将永远处于可变的状态, 即使在一个const函数中

mutable 的用法示例

  1. 普通类的 mutable 成员
#include <iostream>
#include <string>class Logger {
private:mutable int logCount;  // 用于统计日志记录次数,可变
public:Logger() : logCount(0) {}void logMessage(const std::string& message) const {++logCount;  // 即使在 const 函数中,也允许修改std::cout << "Log: " << message << " (Log #" << logCount << ")\n";}
};int main() {const Logger logger;  // 声明一个 const对象logger.logMessage("Program started");  // 依然可以修改logCountlogger.logMessage("Processing data");return 0;
}

输出

Log: Program started (Log #1)
Log: Processing data (Log #2)

在上面的例子中:

  • 类的 logCount 成员变量是用 mutable 修饰的。
  • 即使 Logger 对象是 constlogCount 仍然可以在 logMessage 函数中被修改。
  1. const 对象中的 mutable 使用
#include <iostream>class MyClass {
private:mutable int counter;  // 可变成员
public:MyClass() : counter(0) {}void increment() const {++counter;  // 修改可变成员}int getCounter() const {return counter;}
};int main() {const MyClass obj;  // 声明 const 对象obj.increment();    // 修改 mutable 成员obj.increment();std::cout << "Counter: " << obj.getCounter() << std::endl;return 0;
}

输出

Counter: 2

使用 mutable 时应明确需求,通常用于辅助性的、不影响对象逻辑状态的数据成员。例如:

  • 缓存计算值。
  • 日志或调试计数器。

const_cast 的对比

  • mutable 是在类设计阶段明确指定的“可变性”。
  • const_cast 是临时移除 const 限制,常用于特殊需求。

typedef

用途: 1、为名称复杂的变量创建别名; 2、创建与平台无关的变量,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。 另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。 比如:size_t的介绍

// 在vs中,short 2个字节,int 4个,long也是4个,long long 8个
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
// 在Linux下,short 2个,int 4 个,long 8个,long long 也是8个
typedef short int16_t;
typedef int int32_t;
typedef long int64_t;

所以在程序源码中,只使用这些在头文件中声明的别名。 参考:typedef用法详解

总结与建议

  • 内存管理:明确堆和栈的用途,动态内存需及时释放,避免内存泄漏。
  • 关键字使用
    • static 管理变量作用域和生命周期。
    • 优先使用 inlineconstexpr 替代宏定义。
    • const 提升代码的安全性和优化性能。
    • 谨慎使用 mutable,仅在必要时放宽 const 限制。
    • typedef 或现代 using 提高类型定义的灵活性。

Blog:C++内存布局以及常用关键字

村上春树说:“跑步时我什么都不想,只是奔跑。跑步时我只感受跑步本身。”

编程时亦如此,专注写好每段代码,感受语言的精妙与力量(怎么有语文结尾升华主题那味儿了,笑死ψ(`∇´)ψ,哈哈)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/485449.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式:19、桥接模式

目录 0、定义 1、桥接模式的四种角色 2、桥接模式的UML类图 3、示例代码 0、定义 将抽象部门与实现部分分离&#xff0c;使它们都可以独立地变化。 1、桥接模式的四种角色 抽象&#xff08;Abstraction&#xff09;&#xff1a;一个抽象类&#xff0c;包含实现者&#xf…

Linux中文件操作

文件由文件内容和文件属性构成&#xff0c;因此对文件的操作就是对文件内容或文件属性的操作。所谓的“打开一个文件”就是将文件的属性或内容加载到内存中&#xff0c;而没有被打开的文件存在于磁盘上。打开的文件称作“内存文件”&#xff0c;未被打开的文件称作“磁盘文件”…

elasticsearch基础总结

最近实习&#xff0c;项目用的elasticseatch做的存储库&#xff0c;但是之前对于es接触的不多&#xff0c;查询语法有些不熟&#xff0c;每次想写个DSL查询时都要gpt或者施展搜索大法&#xff0c;所以索性就自己总结总结&#xff0c;以后忘了也方便查。所以这篇文章会持续更新。…

c++ map对其值排序

无法直接排序,转换成vector<std::pair<string,int>> #include <iostream> #include <map> #include <vector> #include <algorithm>// 用于排序的比较函数 bool compareByValue(const std::pair<std::string, int>& a, const …

PysimpleGUI试用版变更免费版

1、PysimpleGUI试用版&#xff1a; 由于5.0版本之后不是免费的 2、变更版本&#xff1a; 打开pycharm-设置-python解释器&#xff1a;点击 搜索PysimpleGUI-指定版本-选择低于5.0的版本&#xff1a;安装软件包 3、重新运行PysimpleGUI&#xff0c;即可获得免费版&#xff1a;…

Grule前端表单post后端执行grule引擎规则

Grule前端表单post后端执行grule引擎规则 编写前端表单和后端接口 编写test.go执行grule引擎规则 示例都是 go test 执行的测试代码&#xff0c;所以将里面的测试代码去除 由于之前 NumberExponentExample_test.go 已经验证可运行, 所以将 err 的异常处理去除 package mai…

STM32串口接收与发送(关于为什么接收不需要中断而发生需要以及HAL_UART_Transmit和HAL_UART_Transmit_IT的区别)

一、HAL_UART_Transmit和HAL_UART_Transmit_IT的区别 1. HAL_UART_Transmit_IT&#xff08;非阻塞模式&#xff09;&#xff1a; HAL_UART_Transmit_IT 是非阻塞的传输函数&#xff0c;也就是说&#xff0c;当你调用 HAL_UART_Transmit_IT 时&#xff0c;它不会等到数据完全发…

使用R语言优雅的获取任意区域的POI,道路,河流等数据

POI是“Polnt of Information”的缩写&#xff0c;中文可以翻译为“信息点”。是地图上任何非地理意义的有意义的点&#xff0c;如商店&#xff0c;酒吧&#xff0c;加油站&#xff0c;医院&#xff0c;车站等。POI&#xff0c;道路网&#xff0c;河流等是我们日常研究中经常需…

七、docker registry

七、docker registry 7.1 了解Docker Registry 7.1.1 介绍 registry 用于保存docker 镜像&#xff0c;包括镜像的层次结构和元数据。启动容器时&#xff0c;docker daemon会试图从本地获取相关的镜像&#xff1b;本地镜像不存在时&#xff0c;其将从registry中下载该镜像并保…

目标跟踪算法:SORT、卡尔曼滤波、匈牙利算法

目录 1 目标检测 2 卡尔曼滤波 3《从放弃到精通&#xff01;卡尔曼滤波从理论到实践》视频简单学习笔记 3.1 入门 3.2 进阶 3.2.1 状态空间表达式 3.2.2 高斯分布 3.3 放弃 3.4 精通 4 匈牙利算法 5 《【运筹学】-指派问题&#xff08;匈牙利算法&#xff09;》视…

OpenCV-图像阈值

简单阈值法 此方法是直截了当的。如果像素值大于阈值&#xff0c;则会被赋为一个值&#xff08;可能为白色&#xff09;&#xff0c;否则会赋为另一个值&#xff08;可能为黑色&#xff09;。使用的函数是 cv.threshold。第一个参数是源图像&#xff0c;它应该是灰度图像。第二…

【HarmonyOS NEXT】实现Tabs组件的TabBar从左到右依次排列

一、背景 系统提供的Tabs目前只能居中展示&#xff0c;暂不支持居左显示&#xff0c;现有的需求是需要Tabs从左往右排列显示&#xff0c;考虑通过Scroll和Row组件来实现 二、实现思路 通过Scroll和Row组件用来实现一个页签&#xff0c;在onclick事件中通过修改索引值和Tabs组…

16-03、JVM系列之:内存与垃圾回收篇(三)

JVM系列之&#xff1a;内存与垃圾回收篇(三) ##本篇内容概述&#xff1a; 1、执行引擎 2、StringTable 3、垃圾回收一、执行引擎 ##一、执行引擎概述 如果想让一个java程序运行起来&#xff0c;执行引擎的任务就是将字节码指令解释/编译为对应平台上的本地机器指令才可以。 简…

FPGA工作原理、架构及底层资源

FPGA工作原理、架构及底层资源 文章目录 FPGA工作原理、架构及底层资源前言一、FPGA工作原理二、FPGA架构及底层资源 1.FPGA架构2.FPGA底层资源 2.1可编程输入/输出单元简称&#xff08;IOB&#xff09;2.2可配置逻辑块2.3丰富的布线资源2.4数字时钟管理模块(DCM)2.5嵌入式块 …

【JVM】JVM基础教程(一)

目录 初识JVM JVM是什么&#xff1f; JVM的功能 解释、即时编译和运行 内存管理 常见的JVM JVM虚拟机规范 HotSpot的发展历程 JVM的组成 字节码文件详解 应用场景 以正确姿势打开字节码文件 ​编辑字节码文件的组成 基本信息 Magic魔数 主副版本号 常量池 接口…

无监督学习笔记 - A Cookbook of Self-Supervised Learning

无监督学习笔记 参考资料&#xff1a; 无监督学习Cookbook 几乎总结了所有的自监督学习方法,阅读过程中&#xff0c;根据参考文献索&#xff0c;进一步深入阅读每个方法具体得细节&#xff0c;掌握该论文&#xff0c;基本上就掌握了所有自监督学习的方法与基础。 统计学习方法…

Trimble X9三维激光扫描仪高效应对化工厂复杂管道扫描测绘挑战【沪敖3D】

化工安全关系到国计民生&#xff0c;近年来随着化工厂数字化改革不断推进&#xff0c;数字工厂逐步成为工厂安全管理的重要手段。而化工管道作为工厂设施的重要组成部分&#xff0c;由于其数量多、种类繁杂&#xff0c;一直是企业管理的重点和难点。 传统的化工管廊往往缺乏详…

synchronized的特性

1.互斥 对于synchronized修饰的方法及代码块不同线程想同时进行访问就会互斥。 就比如synchronized修饰代码块时&#xff0c;一个线程进入该代码块就会进行“加锁”。 退出代码块时会进行“解锁”。 当其他线程想要访问被加锁的代码块时&#xff0c;就会阻塞等待。 阻塞等待…

【vue3 for beginner】Pinia基本用法:存储user的信息

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 Pinia 简介 Pinia 是一个用于 Vue.js 应用的状态管理库&#xff0c;是 Vuex 的…

动态规划(二) ---斐波那契型深度解析

一、使用最小花费爬楼梯 题目链接&#xff1a;746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a;给你一个整数数组 cost &#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用&#xff0c;即可选择向上爬一…