《C++ 基础进阶:内存开辟规则、类型转换原理与 IO 流高效使用》

《C++ 基础进阶:内存开辟规则、类型转换原理与 IO 流高效使用》
前引:在 C++ 编程中,内存管理是程序稳定性与性能的基石,而类型转换与 IO 流则是数据处理和交互的核心工具。栈与堆作为内存分配的两大核心区域,其开辟方式直接决定了变量的生命周期、访问效率及内存安全 —— 错误的分配策略可能导致内存泄漏、野指针或栈溢出等致命问题。与此同时,类型转换的合理性关乎类型系统的严谨性,不当转换易引发数据截断、逻辑错误;IO 流作为数据输入输出的桥梁,其正确使用则直接影响程序与外部设备(如控制台、文件)交互的可靠性!

目录

【一】内存完美开辟

(1)栈和堆的本质区别

(2)如何只在栈上开辟空间

(3)如何只在堆上开辟空间

【二】C++的四种类型转换

(1)static_cast

(2)reinterpret_cast

(3)const_cast

(4)dynamic_cast

【三】operator类型转换

(1)奇怪的现象

(2)类型转化的本质


【一】内存完美开辟

(1)栈和堆的本质区别
栈上开辟:比如一个函数、变量、数组等不需要明确的去malloc、new等申请动态空间

堆上开辟:需要手动去开辟指定大小的空间以及释放
特性栈(Stack)堆(Heap)
分配方式编译器自动分配 / 释放程序员手动分配(new)/ 释放(delete
生命周期随作用域(如函数、代码块)结束而销毁delete调用而销毁(否则内存泄漏)
大小限制通常较小(如几 MB,由系统限制)较大(几乎等于系统可用内存)
速度极快(类似 “拿取 / 放回固定货架”)较慢(类似 “找空地放东西,还要记录位置”)
使用场景局部变量、函数参数等短期存在的变量动态大小的数据(如数组长度运行时确定)
(2)如何只在栈上开辟空间

栈上开辟不需要手动的去malloc、new动态内存,周期一般在该函数调用结束时自动销毁

我们知道动态开辟,比如C++的new形式开辟是调用operator new开辟堆空间的,因此解决如下:

禁用(私有)operator new这样用户就没法调用,那就只能在栈上开辟空间,实现如下:

template<class T> class StackOnly { public: StackOnly() { } private: // 将operator new设为私有,禁止堆分配 void* operator new(size_t size); void operator delete(void* ptr); };
(3)如何只在堆上开辟空间

堆上调用是明确的调用new开辟空间,而栈每次是调用构造函数,因此我们禁用(私有)构造函数,只放new出来就可以完成只在堆上开辟空间,实现如下:

class HeapOnly { private: // 构造函数私有,禁止栈上创建(栈上创建需要调用构造函数) HeapOnly() {} public: // 静态函数:在堆上创建对象并返回指针 static HeapOnly* create() { return new HeapOnly(); } ~HeapOnly() { delete this; // 释放当前对象 } }; 
这里为什么要用static静态修饰这个create函数?
简洁解释:若不用static修饰,这个函数就属于对象,就要调用构造函数。而用static修饰之后,这个函数就属于类本身,不需要创建对象就可以调用,就可以避免先有对象再调用函数

详细解释如下:

栈上创建对象时,需要直接调用构造函数(比如 HeapOnly obj; 会触发构造函数)。但我们为了禁止栈上创建,把构造函数设为了 private(外部无法直接调用)此时,如果 create 不是静态函数:非静态函数属于对象(需要先有一个 HeapOnly 对象才能调用)。但构造函数私有,根本无法在外部创建第一个 HeapOnly 对象,自然也无法调用非静态的 create。而 静态成员函数属于 “类本身”,不需要先创建对象就能调用(可以直接通过 类名::函数名 调用,比如 HeapOnly::create())。这样就能绕开 “必须先有对象才能调用函数” 的限制,在 create 内部用 new (调用私有构造函数)创建堆上的对象

【二】C++的四种类型转换

介绍:在 C++ 中,类型转换是程序中常见的操作,为了使转换行为更清晰、更安全,C++ 提供了四种显式类型转换运算符(也称为 “转换的类模板”),分别是static_castdynamic_castconst_castreinterpret_cast。它们各自有明确的适用场景和特性!

(1)static_cast
static_cast一般用于相近类型的转化

比如 int 和 double,:

int a = 10; double b = static_cast<double>(a);

比如 char 和 long:

char c = 'c'; long d = static_cast<long>(c);
(2)reinterpret_cast
reinterpret_cast一般用于不相关类型转化

比如:int *  和 double *

int* c = &a; double* d = reinterpret_cast<double*> (c);

比如:char* 和 double*

char* c = &c; double* d = reinterpret_cast<double*> (c);
(3)const_cast
const_cast一般用于去掉const

例如:

int x = 10; // 本质是非const对象 const int* pc = &x; // const指针指向非const对象(仅限制通过该指针修改) // 需求:需要通过指针修改x的值 int* non_const_ptr = const_cast<int*>(pc); // 移除const
(4)dynamic_cast
dynamic_cast一般用于继承上的父->子的转化

(父类的指针是可以指向子类的对象的->切片)

(子类的指针是不可以指向父类的对象的)

例如:

class A { public: virtual void f() {} int _x = 0; }; class B : public A { public: int _y = 0; }; void fun(A* pa) { // pa是指向子类对象B的,转换可以成功,正常返回地址 // pa是指向父类对象A的,转换失败,返回空指针 B* pb = dynamic_cast<B*>(pa); if (pb) { cout << "转换成功" << endl; pb->_x++; pb->_y++; } else { cout << "转换失败" << endl; } }

【三】operator类型转换

(1)奇怪的现象

例如现在有一个类:

class Func { public: int a = 10; operator bool() { return a; } }; 

现在我们创建一个Func类类型的对象A,并进行赋值:

int main() { Func A; bool pc = A; cout << pc << endl; return 0; }
问:一个对象怎么赋值给一个变量呢?

但是结果是可以的,我们看下面的运行结果:

(2)类型转化的本质
运算符重载的本质是重新定义运算符的行为,让自定义类型(类)能像内置类型(如 intdouble)一样使用运算符运算符选择:大部分 C++ 运算符都可重载(如 +-=<< 等),但少数不可重载(如 .::sizeof?: 三目运算符)类型转换运算符(特殊的运算符重载):用于将类对象转换为其他类型(如 boolintdouble 等)语法上没有显式的返回值类型(返回值类型由 “operator 目标类型” 决定),也没有参数(因为是 “将当前对象转换为目标类型”)。示例:operator int() 表示 “将对象转换为 int 类型”,operator double() 表示 “将对象转换为 double 类型”

Read more

Flutter 三方库 ff_annotation_route 的鸿蒙化适配指南 - 掌握基于注解的自动化路由管理技术、助力鸿蒙大型 HAP 项目构建极速解构且类型安全的页面跳转体系

Flutter 三方库 ff_annotation_route 的鸿蒙化适配指南 - 掌握基于注解的自动化路由管理技术、助力鸿蒙大型 HAP 项目构建极速解构且类型安全的页面跳转体系

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 ff_annotation_route 的鸿蒙化适配指南 - 掌握基于注解的自动化路由管理技术、助力鸿蒙大型 HAP 项目构建极速解构且类型安全的页面跳转体系 前言 在 OpenHarmony 鸿蒙应用向“大规模、模块化、组件化”演进的工程实战中,路由(Routing)管理始终是维护成本最高的环节之一。传统的硬编码路由表(String-based Routes)在面对数百个页面时,极易出现拼写错误、参数透传混乱以及耦合度过高等问题。如何实现“写完页面,路由自动生成”?如何让每一个页面跳转都具备强类型校验?ff_annotation_route 作为一个专注于“注解驱动自动化”的路由生成引擎,旨在为鸿蒙开发者提供一套工业级的路由治理方案。本文将详述其在鸿蒙端的实战技法。 一、原原理分析 / 概念介绍 1.1

By Ne0inhk
Flutter 组件 fluent_assertions 的适配 鸿蒙Harmony 实战 - 驾驭流式语义断言语法、实现鸿蒙端单元测试高可读性与复杂逻辑自证方案

Flutter 组件 fluent_assertions 的适配 鸿蒙Harmony 实战 - 驾驭流式语义断言语法、实现鸿蒙端单元测试高可读性与复杂逻辑自证方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 fluent_assertions 的适配 鸿蒙Harmony 实战 - 驾驭流式语义断言语法、实现鸿蒙端单元测试高可读性与复杂逻辑自证方案 前言 在鸿蒙(OpenHarmony)生态的大型分布式系统开发中,随着业务逻辑复杂度的指数级增长,原本简单的单元测试逐渐演变为由数百行冗长、枯燥且难以通过阅读理解其意图的 expect(result, isA<T>()) 堆砌而成的“代码仓库”。面对一个需要同时验证“返回值不为空 且 包含特定前缀 且 响应时间小于 50ms”的复合业务断言。如果仅仅依靠传统的 JUnit 风格写法。不仅会导致测试代码本身产生严重的维护债务,更会由于在测试失败时生成的机械化、无逻辑上下文的错误报文,引发开发者极其低效的排查过程。 我们需要一种“自然语言化、逻辑链式”的测试审计艺术。 fluent_

By Ne0inhk
黑苹果macos 15 Sequoia升级 macos 26.1 Tahoe小结

黑苹果macos 15 Sequoia升级 macos 26.1 Tahoe小结

macos tohoe 升级记录 1、下载系统包 在https://macoshome.com/macos/73876.html下载 pkg 包,下载后打开安装 2、 在OCAuxiliaryTools.app升级 opencore 至 1.0.6,更新后根据工具提示修改 OC配置文件,最重要是修改机型(要选比较新的机型,如macbook pro 16,4)、生成三码 修改下载地址为 github,比默认要快很多 3、 github下载替换Lilu、AppleALC.kext、WhateverGreen.kext最新版 4、打开 第一步安装好的 macos Tahoe,按提示继续,直至重启 5、进系统后,关闭文件保险箱,

By Ne0inhk
Flutter 组件 http_interop 的适配 鸿蒙Harmony 实战 - 驾驭跨平台通讯互操作标准、实现鸿蒙端 HTTP 客户端深度解耦与协议中继方案

Flutter 组件 http_interop 的适配 鸿蒙Harmony 实战 - 驾驭跨平台通讯互操作标准、实现鸿蒙端 HTTP 客户端深度解耦与协议中继方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 http_interop 的适配 鸿蒙Harmony 实战 - 驾驭跨平台通讯互操作标准、实现鸿蒙端 HTTP 客户端深度解耦与协议中继方案 前言 在鸿蒙(OpenHarmony)生态的大型微服务矩阵集成、跨机构 API 网关桥接、以及需要在一个应用中同时引入多个依赖于不同网络库(如 dio, http, cronet)的三方组件开发中,“网络协议栈的互操作性(Interop)”是解决工程依赖地狱的终极武器。面对某些历史遗留的三方库硬编码了特定版本的请求 client。 如果我们无法实现对这些 client 的无感平替与标准化包装。那么不仅会导致在鸿蒙端产生多个冗余的网络连接池造成系统资源浪费。更会因为无法在全局层面注入统一的鉴权(Auth)与加密(Crypto)中间件,引发严重的合规性风险。 我们需要一种“接口中道、请求无间”的互操作艺术。 http_

By Ne0inhk