栈/堆/static/虚表

在 C++ 里,栈空间主要用来存放局部变量、函数调用信息等。下面为你介绍栈空间在 C++ 里的运用方式。

1. 局部变量的使用

在函数内部定义的变量会被存于栈空间,当函数执行结束,这些变量会自动被销毁。

#include <iostream>void exampleFunction() {// 定义一个局部变量,存于栈空间int localVar = 10;std::cout << "Local variable value: " << localVar << std::endl;
}int main() {exampleFunction();return 0;
}

2. 函数调用栈

每次调用函数时,系统会在栈上为该函数创建一个栈帧,用来保存函数的局部变量、参数、返回地址等信息。函数返回时,对应的栈帧会被销毁。

#include <iostream>void func2(int value) {std::cout << "Value in func2: " << value << std::endl;
}void func1() {int localVar = 20;func2(localVar);
}int main() {func1();return 0;
}

3. 递归调用

递归函数是在函数内部调用自身,每次递归调用都会在栈上创建新的栈帧。要注意递归深度,防止栈溢出。

#include <iostream>// 递归计算阶乘
int factorial(int n) {if (n == 0 || n == 1) {return 1;}return n * factorial(n - 1);
}int main() {int num = 5;std::cout << "Factorial of " << num << " is: " << factorial(num) << std::endl;return 0;
}

栈空间使用的注意事项

  • 栈溢出:若栈空间使用过多,例如递归过深或者局部变量占用空间过大,就会引发栈溢出错误。
  • 生命周期:栈上的变量生命周期局限于定义它的代码块,出了代码块就会被销毁。

在 C++ 中,堆空间用于动态分配内存,可在程序运行时根据需要分配和释放内存。下面详细介绍堆空间的使用方法。

1. 使用 new 和 delete 操作符进行内存分配和释放

  • 分配单个对象:使用 new 操作符为单个对象分配内存,使用 delete 操作符释放内存。
#include <iostream>int main() {// 在堆上分配一个 int 类型的对象int* ptr = new int;*ptr = 42;std::cout << "Value: " << *ptr << std::endl;// 释放堆上的内存delete ptr;return 0;
}
  • 分配数组:使用 new[] 操作符为数组分配内存,使用 delete[] 操作符释放内存。
#include <iostream>int main() {// 在堆上分配一个包含 5 个 int 元素的数组int* arr = new int[5];for (int i = 0; i < 5; ++i) {arr[i] = i;}// 输出数组元素for (int i = 0; i < 5; ++i) {std::cout << arr[i] << " ";}std::cout << std::endl;// 释放堆上的数组内存delete[] arr;return 0;
}

2. 使用智能指针管理堆内存

为了避免手动管理内存带来的内存泄漏问题,C++ 提供了智能指针。常用的智能指针有 std::unique_ptrstd::shared_ptr 和 std::weak_ptr

  • std::unique_ptr:独占所指向的对象,同一时间只能有一个 std::unique_ptr 指向该对象。
#include <iostream>
#include <memory>int main() {// 使用 std::unique_ptr 管理堆上的 int 对象std::unique_ptr<int> ptr = std::make_unique<int>(42);std::cout << "Value: " << *ptr << std::endl;// 不需要手动释放内存,std::unique_ptr 会在离开作用域时自动释放return 0;
}
  • std::shared_ptr:多个 std::shared_ptr 可以共享同一个对象,使用引用计数来管理对象的生命周期。
#include <iostream>
#include <memory>int main() {// 使用 std::shared_ptr 管理堆上的 int 对象std::shared_ptr<int> ptr1 = std::make_shared<int>(42);std::shared_ptr<int> ptr2 = ptr1;std::cout << "Value: " << *ptr2 << std::endl;// 当所有指向该对象的 std::shared_ptr 都被销毁时,对象会自动释放return 0;
}

3. 自定义类对象的堆内存管理

在自定义类中,需要注意析构函数的实现,确保在对象销毁时正确释放堆上的内存。

#include <iostream>class MyClass {
private:int* data;
public:MyClass(int value) {// 在构造函数中分配堆内存data = new int(value);}~MyClass() {// 在析构函数中释放堆内存delete data;}int getValue() const {return *data;}
};int main() {MyClass obj(42);std::cout << "Value: " << obj.getValue() << std::endl;return 0;
}

堆空间使用的注意事项

  • 内存泄漏:如果使用 new 分配了内存,但没有使用 delete 或 delete[] 释放,或者智能指针管理不当,会导致内存泄漏。
  • 悬空指针:释放内存后,指针仍然指向原来的内存地址,使用这样的指针会导致未定义行为。

4.C/C++ 中static的作用

  • 静态局部变量:在函数内部用static修饰的局部变量,存储在全局数据区而非栈区。它的生命周期贯穿整个程序运行期间,在程序执行到其声明处时首次初始化,之后的函数调用不再初始化;若未显式初始化,会自动初始化为 0 。其作用域仍在定义它的函数内部。常用于记录函数调用次数或状态
  • 静态全局变量:在全局变量前加static,该变量存储在全局数据区,作用域为声明它的文件,其他文件即使使用extern声明也无法访问。可提高程序的封装性,防止全局变量被意外修改,还能避免多文件项目中不同文件同名全局变量的命名冲突。比如在一个多人协作的大型项目中,每个源文件里的静态全局变量只在本文件内有效,不同文件可使用相同变量名。
  • 静态函数:被static修饰的函数只能在声明它的文件中可见和调用,不能被其他文件使用。有助于提高程序的封装性,减少函数被其他文件错误调用的风险
  • 类的静态数据成员:在类内数据成员声明前加static,该数据成员为类的所有对象共享,在程序中只有一份拷贝,存储在全局数据区。
  • 类的静态成员函数:用static修饰的类成员函数,属于类本身而非类的对象,没有this指针,不能直接访问非静态成员变量和非静态成员函数。可在创建对象前调用,常作为工具函数或用于访问静态数据成员。

--------------------------------------------------------------------------------------------------------------------------------------关于一个函数的地址这里可以提到的是。函数名就是一个函数的地址!但是不能查地址的时候忽略作用域

关于函数指针问题:typedef void (*PluginFunction)();首先PluginFunction它是这个指针的别名,最后的一个括号说明这个指针可以用于没有参数的函数!

#include <iostream>// 定义一个插件函数
void pluginFunction() {std::cout << "This is a plugin function." << std::endl;
}// 使用函数指针类型表示插件函数类型
typedef void (*PluginFunction)();// 主程序加载插件并调用插件函数
void loadAndCallPlugin(PluginFunction func) {func();
}int main() {loadAndCallPlugin(pluginFunction);return 0;
}

从这个图也可以看出虚表也是存在于常量区代码段的位置!

5.多继承的虚表

//多继承的虚函数表
class Base1 {
public:virtual void func1() { std::cout << "Base1::func1" << std::endl; }virtual void func2() { std::cout << "Base1::func2" << std::endl; }
private:int b1;
};class Base2 {
public:virtual void func1() { std::cout << "Base2::func1" << std::endl; }virtual void func2() { std::cout << "Base2::func2" << std::endl; }
private:int b2;
};class Derive : public Base1, public Base2 {
public:virtual void func1() { std::cout << "Derive::func1" << std::endl; }virtual void func3() { std::cout << "Derive::func3" << std::endl; }
private:int d1;
};

derive内有两个虚表的原因:分别是Base1内的一个虚表,Base2一个续表,而func3会通过编译器自动放在一个已有的虚表中。

C++ 编译器为每个包含虚函数的类生成虚函数表,目的是为了实现运行时多态。当一个类继承自多个基类,且基类都有虚函数时,该派生类会继承基类的虚表结构。编译器通常会复用已有的虚表,将新的虚函数指针添加到合适的虚表中,而不是为每个新虚函数单独创建一个虚表。这样可以节省内存空间,并保持虚函数调用机制的一致性。

 

 

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

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

相关文章

SpringBoot实现异步调用的方法

在Java中使用Spring Boot实现异步请求和异步调用是一个常见的需求&#xff0c;可以提高应用程序的性能和响应能力。以下是实现这两种异步操作的基本方法&#xff1a; 一、异步请求&#xff08;Asynchronous Request&#xff09; 异步请求允许客户端发送请求后立即返回&#x…

基于 Prompt 的实体关系抽取:原理与优势解析

一、信息抽取的现状与挑战 在当今数字化时代&#xff0c;信息抽取作为自然语言处理&#xff08;NLP&#xff09;领域的核心技术&#xff0c;具有不可替代的重要性。从海量的非结构化文本数据中精准提取出有价值的信息&#xff0c;例如实体&#xff08;如人名、组织名&#xff…

SolidWorks使用显卡教程

操作步骤&#xff1a; 打开注册表编辑器 按下键盘上的 Win R 组合键&#xff0c;输入 regedit 并按回车键&#xff0c;打开注册表编辑器。 导航到显卡信息路径 在注册表中依次展开以下路径&#xff1a; plaintext HKEY_CURRENT_USER\Software\SolidWorks\SOLIDWORKS 2021\Per…

spring-tx笔记

编程式事务与声明式事务的理解 补充&#xff1a;什么是事务&#xff1f; 事务是一个重要概念&#xff0c;尤其在数据库管理系统中。事务是指一组操作。&#xff0c;这些操作要么全部成功执行&#xff0c;要么全部不执行&#xff0c;确保数据的一致性和完整性 编程式事务 编…

使用excel.EasyExcel实现导出有自定义样式模板的excel数据文件,粘贴即用!!!

客户要求导出的excel文件是有好看格式的&#xff0c;当然本文举例模板文件比较简单&#xff0c;内容丰富的模板可以自行设置&#xff0c;话不多说&#xff0c;第一步设置一个"好看"的excel文件模板 上面要注意的地方是{.变量名} &#xff0c;这里的变量名对应的就是…

AutoGluon快速上手

我叫不三不四&#xff0c;很高兴见到大家&#xff0c;欢迎一起学习交流和进步 今天来讲一讲机器学习包 AutoGluon简介&#xff1a; AutoGluon 提供了多种模型来处理不同类型的数据和任务&#xff0c;是由 亚马逊 AWS 团队 开发的一款开源 AutoML 框架&#xff0c;旨在简化机器…

AI风向标《AI与视频制作全攻略:从入门到精通实战课程》

课程信息 AI风向标《AI与视频制作全攻略&#xff1a;从入门到精通实战课程》,夸克网盘和百度网盘课程。 课程介绍 《AI与视频制作全攻略&#xff1a;从入门到精通实战课程》是一套全面融合AI技术与视频制作的实战课程&#xff0c;旨在帮助创作者从基础软件使用到高级视频剪辑…

Docker学习笔记(十)搭建Docker私有仓库

一、环境配置 1、宿主机系统&#xff1a;macOS Sequoia(版本15.2) 2、虚拟机VMware Fusion版本&#xff1a;专业版 13.6.2 (24409261) 3、虚拟机系统&#xff1a;AlmaLinux-9-latest-x86_64-boot.iso 二、安装Harbor开源企业级Docker镜像 Harbor 是一个开源的企业级 Docker…

Linux中基本命令

目录 ls pwd cd touch mkdir rm cp mv cat less head tail find grep ls 其实大部分命令都是可执行的文件&#xff0c;但有一些命令比如Shell内置命令&#xff0c;它没有对应的独立可执行文件&#xff0c;而是由Shell直接解释执行的。 功能&#xff1a;显示当前目…

IDEA导入jar包后提示无法解析jar包中的类,比如无法解析符号 ‘log4j‘

IDEA导入jar包后提示无法解析jar包中的类 问题描述解决方法 问题描述 IDEA导入jar包的Maven坐标后&#xff0c;使用jar中的类比如log4j&#xff0c;仍然提示比如无法解析符号 log4j。 解决方法 在添加了依赖和配置文件后&#xff0c;确保刷新你的IDE项目和任何缓存&#xff…

字节跳动实习生主导开发强化学习算法,助力大语言模型性能突破

目录 禹棋赢的背景与成就 主要成就 DAPO算法的技术细节 算法优势 禹棋赢的研究历程 关键时间节点 字节跳动的“Top Seed人才计划” 计划特点 小编总结 在大模型时代&#xff0c;经验不再是唯一的衡量标准&#xff0c;好奇心、执行力和对新技术的敏锐洞察力成为推动技术…

Mysql表的简单操作

&#x1f3dd;️专栏&#xff1a;Mysql_猫咪-9527的博客-CSDN博客 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 3.1 创建表 3.2 查看表结构 3.3 修改表 1. 添加字段 2. 修改字段 …

【一起学Rust | Tauri2.0框架】基于 Rust 与 Tauri 2.0 框架实现全局状态管理

前言 在现代应用程序开发中&#xff0c;状态管理是构建复杂且可维护应用的关键。随着应用程序规模的增长&#xff0c;组件之间共享和同步状态变得越来越具有挑战性。如果处理不当&#xff0c;状态管理可能会导致代码混乱、难以调试&#xff0c;并最终影响应用程序的性能和可扩…

大模型的微调技术(高效微调原理篇)

背景 公司有需求做农业方向的大模型应用以及Agent助手&#xff0c;那么适配农业数据就非常重要。但众所周知&#xff0c;大模型的全量微调对算力资源要求巨大&#xff0c;在现实的限制条件下基本“玩不起”&#xff0c;那么高效微调技术就非常必要。为了更好地对微调技术选型和…

Java 大视界 -- Java 大数据在智能家居设备联动与场景自动化中的应用(140)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

面试八股 —— Redis篇

重点&#xff1a;缓存 和 分布式锁 缓存&#xff08;穿透&#xff0c;击穿&#xff0c;雪崩&#xff09; 降级可作为系统的保底策略&#xff0c;适用于穿透&#xff0c;击穿&#xff0c;雪崩 1.缓存穿透 2.缓存击穿 3.缓存雪崩 缓存——双写一致性 1.强一致性业务&#xff08…

[网络安全] 滥用Azure内置Contributor角色横向移动至Azure VM

本文来源于团队的超辉老师&#xff0c;其系统分析了Azure RBAC角色模型及其在权限滥用场景下的攻击路径。通过利用AADInternals工具提升用户至Contributor角色&#xff0c;攻击者可在Azure VM中远程执行命令&#xff0c;创建后门账户&#xff0c;实现横向移动。文中详述了攻击步…

OO_Unit1

第一次作业 UML类图 代码复杂度分析 其中Expr中的toString方法认知复杂度比较高&#xff0c;主要源于多层条件嵌套和分散的字符串处理逻辑&#xff0c;重构时可重点关注这两部分的解耦。 代码量分析 1.”通用形式“ 我觉得我的设计的最大特点就是“通用形式”&#xff0c;具…

阿里云 AI 搜索产品荣获 Elastic Innovation Award 2024

阿里云AI搜索产品荣获Elastic Innovation Award 2024&#xff0c;该奖项于近日在新加坡ElasticON 2025的Elastic合作伙伴峰会上颁发&#xff0c;旨在表彰基于Elastic平台开发企业级生成式人工智能&#xff08;GenAI&#xff09;应用的顶尖合作伙伴&#xff0c;这些应用有效帮助…

网络原理之网络层、数据链路层

1. 网络层 1.1 IP协议 1.1.1 基本概念 主机: 配有IP地址,但是不进⾏路由控制的设备路由器: 即配有IP地址,⼜能进⾏路由控制节点: 主机和路由器的统称 1.1.2 协议头格式 说明&#xff1a; 4位版本号(version): 指定IP协议的版本,对于IPv4来说,就是4,对于IPv6来说,就是6 4位头…