C++内存布局(一)

温故而知新,本文浅聊和回顾下C++内存布局的知识。

一、c++内存布局

C++的内存布局主要包括以下几个部分:

  • 代码段:存储程序的机器代码。
  • .数据段:存储全局变量和静态变量。数据段又分为初始化数据段(存储初始化的全局变量和静态变量)和未初始化数据段(存储未初始化的全局变量和静态变量)。
  • :用于动态内存分配。当你使用new或malloc函数时,内存会从堆中分配。
  • :用于存储局部变量和函数调用的信息(例如返回地址和参数)。当你调用一个函数时,一个新的栈帧会被压入栈,当函数返回时,这个栈帧会被弹出。
  • 常量段:存储常量字符串和其他常量。

代码示例

#include <iostream>

int global_var = 0;  // 初始化的全局变量,存储在初始化数据段
int uninit_global_var;  // 未初始化的全局变量,存储在未初始化数据段

void foo() {
    int local_var = 0;  // 局部变量,存储在栈
    static int static_local_var = 0;  // 静态局部变量,存储在初始化数据段
    int* dynamic_var = new int(0);  // 动态分配的内存,地址在堆,dynamic_var指针变量的生命周期是foo函数栈

    std::cout << "local_var: " << &local_var << std::endl;
    std::cout << "static_local_var: " << &static_local_var << std::endl;
    std::cout << "dynamic_var: " << dynamic_var << std::endl;

    delete dynamic_var;  // 释放动态分配的内存
}

int main() {
    std::cout << "global_var: " << &global_var << std::endl;
    std::cout << "uninit_global_var: " << &uninit_global_var << std::endl;

    foo();

    return 0;
}

二、C++ 类的内存布局

C++类的内存布局主要取决于类的数据成员和继承关系。以下是一些基本的规则:

  • 数据成员变量:类的数据成员按照它们在类定义中的顺序存储在内存中。每个数据成员的偏移量是它的类型对齐要求的倍数。
// x64
#pragma pack(push,4) //指定4字节对齐
class TmpClass{}; // 空类sizeof,大小为1

class NoVirtual
{
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};
#pragma pack(pop) 
  • 成员函数:在C++中,成员函数并不直接存储在每个对象中。相反,所有对象共享同一个成员函数的副本。成员函数的代码存储在代码段,而不是每个对象的内存空间。因此,成员函数不影响类的sizeof大小。
    当你调用一个对象的成员函数时,编译器会自动将对象的地址作为隐藏参数传递给成员函数。这个隐藏参数通常被称为this指针。通过this指针,成员函数可以访问调用它的对象的数据成员。
class NoVirtual
{
    void dc(){}	// 成员函数,内存在代码段
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};
  • 静态成员变量:静态成员变量不属于类的任何一个对象,它们在所有对象之间共享。静态成员变量存储在全局数据段,而不是对象的内存空间。

  • 静态成员函数:静态成员函数也不属于类的任何一个对象。它们没有this指针,因此不能访问类的非静态成员。静态成员函数的地址存储在代码段。

  • 继承:如果一个类继承自一个或多个基类,那么基类的数据成员会先于派生类的数据成员存储在内存中。如果有多个基类,那么基类的数据成员按照它们在类定义中的顺序存储。

class Iface
{
public:
    Iface(){MYTRACE();}
    virtual ~Iface(){MYTRACE();}
    virtual void Ifun() = 0;
};


// 继承
class MemLayout : public Iface
{
public:

    MemLayout(){ MYTRACE(); }
    ~MemLayout(){ MYTRACE(); }

    virtual void Ifun() override { MYTRACE(); }

    virtual void dc0(){ MYTRACE(); }
    virtual void dc1(){ MYTRACE(); }

private:
    int m_num = 0;
    static std::string m_desc;
};

std::string MemLayout::m_desc = "hello";

在这里插入图片描述

  • 虚函数:如果一个类有虚函数(virtual关键字修饰),那么编译器会为这个类生成一个虚函数表(vtable: 函数指针数组),并在每个对象中添加一个指向虚函数表的指针(vptr)。虚函数表中存储了虚函数的地址。如果一个类继承自一个有虚函数的基类,那么它会继承基类的虚函数表。
class VirtualClass
{
   virtual  void dc(){}
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};

在这里插入图片描述

  • 虚继承:如果一个类使用虚继承,那么编译器会为这个类生成一个虚基类表(vbtable),并在每个对象中添加一个指向虚基类表的指针。虚基类表中存储了虚基类的偏移量。*直白点说,虚继承的派生类的实例化对象,会包含多张虚函数表的(下面有图为证)~,具体有几个vptr ,我们会在《C++内存布局(二)》中详细研究下,尤其是多重继承和钻石继承的场景下。
    请添加图片描述
class NoVirtual
{
    void dc(){}
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};

class Iface
{
public:
    Iface(){MYTRACE();}
    virtual ~Iface(){MYTRACE();}
    virtual void Ifun() = 0;
};

// 虚继承
class MemLayout : virtual public Iface
{
public:

    MemLayout(){ MYTRACE(); }
    ~MemLayout(){ MYTRACE(); }

    virtual void Ifun() override { MYTRACE(); }

    virtual void dc0(){ MYTRACE(); }
    virtual void dc1(){ MYTRACE(); }

private:
    int m_num = 0;
    static std::string m_desc;
};

std::string MemLayout::m_desc = "hello";

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVM基础原理篇-透彻理解类加载子系统(学习笔记)

一、从Hello World轻松理解类加载的基本过程 1.类加载子系统整体工作过程 大白话&#xff1a; 符号引用 - 相当于建房子的图纸&#xff0c;在字节码文件中 直接引用 - 建房子&#xff0c;在Java的内存模型中 这里需要注意下面的代码 这里为什么先在静态代码块给a赋值20&#xf…

(四)pytorch图像识别实战之用resnet18实现花朵分类(代码+详细注解)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、关于这个实战的一些知识点Q1&#xff1a;图像识别实战常用模块解读Q2:数据增强Q3:迁移学习Q4&#xff1a;平均全局池化Q5&#xff1a;设置哪些层需要训练时…

MongoDB的原子操作findAndReplace、findOneAndDelete和deleteMany

本文主要介绍MongoDB的原子操作findAndReplace、findOneAndDelete和deleteMany。 目录 MongoDB的原子操作一、findAndReplace二、findOneAndDelete三、deleteMany MongoDB的原子操作 MongoDB的原子操作指的是在单个操作中对数据库的数据进行读取和修改&#xff0c;并确保操作是…

JaCoCo 统计度量

1、JaCoCo: 一个判断算2个Branch&#xff0c;最后一个括号算一行 2、IDEA&#xff1a;一个判断算一个Branch&#xff0c;最后一个括号不算一行

代码随想录算法训练营Day5 | 454.四数相加||、383.赎金信、35.三个之和、18.四数之和

LeetCode 454 四数相加 || 本题思路&#xff1a; 如果使用暴力的话就是 4 层 for 循环&#xff0c;这个时间复杂度就是 O(n^4) 了。 所以我们可以使用 map &#xff0c;来解决这道题&#xff0c;和之前的两数之和一样&#xff0c;之前是 遍历一个&#xff0c;存进去一个。 如果…

一个真正的软件测试从业人员必备技能有哪些?

协同开发能力&#xff1a; 1. 项目管理&#xff08;SVN、Git&#xff09; 2. 数据分析能力&#xff08;Fiddler、Charles、浏览器F12&#xff09;。 接口测试&#xff1a; 1. 概念及接口测试原理概念&#xff08;概念、接口测试原理&#xff09; 2. 接口测试工具&#xff…

AWS向量数据库Amazon OpenSearch Service使用测评

前言 在大模型盛行的当今&#xff0c;选择适宜的数据库显得尤为重要。因为你需要面对海量训练数据&#xff0c;快速的检索至关紧要&#xff0c;以及对于存储的要求也是至关重要的。对于海量的数据查询和存储是需要巨大的算力支持。向量数据库常用在一些图像文本或者视频的生成…

硬件基础集线器、交换机、路由器原理

OSI七层模型 OSI介绍 OSI &#xff08;Open System Interconnect&#xff09;模型全称为开放式通信系统互连参考模型&#xff0c;是国际标准化组织 ( ISO ) 提出的一个试图使各种计算机在世界范围内互连为网络的标准框架 OSI将计算机网络体系结构划分为七层&#xff0c;每一…

【SQL】根据年份,查询每个月的数据量

根据年份&#xff0c;查询每个月的数据量 一种 WITH Months AS (SELECT 1 AS Month UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION…

Dokit 开源库:简化 Android 应用开发的利器

Dokit 开源库&#xff1a;简化 Android 应用开发的利器 一、Dokit 简介二、Dokit 功能三、Dokit 使用3.1 DoKit Android 最新版本3.2 DoKit Android 接入步骤 四、总结 在 Android 应用开发过程中&#xff0c;我们经常需要处理调试、性能优化和用户体验等方面的问题。然而&…

Java精品项目源码新基于协同过滤算法的旅游推荐系统(编号V69)

Java精品项目源码新基于协同过滤算法的旅游推荐系统(编号V69) 大家好&#xff0c;小辰今天给大家介绍一个基于协同过滤算法的旅游推荐系统

linux ARM64 处理器内存屏障

一、内存类型&#xff1a; ARMv8架构将系统中所有的内存&#xff0c;按照它们的特性&#xff0c;划分成两种&#xff0c;即普通内存和设备内存。并且它们是互斥的&#xff0c;也就是说系统中的某段内存要么是普通内存&#xff0c;要么是设备内存&#xff0c;不能都是。 1&…

动力电池系统介绍(十四)——热管理系统

动力电池系统介绍&#xff08;十四&#xff09; 一、梗概二、座舱热管理&#xff08;汽车空调&#xff09;2.1 空调制冷2.2 空调制热2.2.1 传统燃油汽车空调制热2.2.2 新能源汽车空调制热 三、动力系统热管理3.1 燃油车发动机热管理3.1.1 冷却系统3.1.2 润滑系统3.1.3 进排气系…

C++ Lambda表达式基础用法

语法 C11标准lambda表达式的语法非常简单&#xff0c;定义如下&#xff0c;并且语法规定lambda表达式如果存在说明符&#xff0c;那么形参列表不能省略。标准还规定能捕获的变量必须是一个自动存储类型。简单来说就是非静态的局部变量、非全局变量。 定义&#xff1a;[ captu…

纳米流体传热与计算机模拟

纳米流体传热与计算机模拟 一、引言 纳米流体传热是一个研究领域&#xff0c;主要关注纳米尺度下流体的传热特性和机制。由于纳米流体的尺寸较小&#xff0c;其传热行为与传统尺度下的流体有很大不同。近年来&#xff0c;随着计算机技术的飞速发展&#xff0c;计算机模拟成为…

TensorFlow(2):Windows安装TensorFlow

1 安装python环境 这一步请自行安装&#xff0c;这边不做介绍。 2 安装anaconda 下载路径&#xff1a;Index of /&#xff0c;用户自行选择自己的需要的版本。 3 环境配置 3.1 anaconda环境配置 找到设置&#xff0c;点击系统->系统信息->高级系统设置->环境变量…

Github 2023-12-19开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-19统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4Rust项目2非开发语言项目2C#项目1TypeScript项目1 Avalonia: 跨平台UI框架和Avalonia XPF 创建周…

高高。。。。

重点&#xff1a;存储系统/分布式系统 得到数据&#xff1a; 数据模型计算&#xff08;简单系统&#xff09;实现一个操作系统CPU&#xff08;成本高&#xff09;仿真实验 文章类型&#xff1a; 国际会议 10-15slices期刊论文 做OS研究为其他方面提供支持 一 Advanced OS …

鸿蒙开发运用ArkUI基础-实操显式动画

利用ArkUI组件不仅可以实现属性变化引起的属性动画&#xff0c;也可以实现父组件状态变化引起子组件产生动画效果&#xff0c;这种动画为显式动画。效果如图所示&#xff1a; 代码结构解读 ├──entry/src/main/ets // 代码区 │ ├──common │ │ └──…

css 美化滚动条

当div内容溢出容器定义的高度时,滚动条显示,并美化默认的滚动条样式 div 容器 <divclass"content">内容 </div>css 样式 /* 问话区域 滚动条 */ .content {overflow: auto;height: 662px;padding: 25px;scrollbar-width: thin; /* 设置滚动条宽度 */bo…