C++移动语义
C++11引入的移动语义是一项重大的性能优化,它允许”窃取”临时对象的资源而非复制,从根本上消除了大量不必要的深拷贝开销。理解移动语义,需要先弄清楚C++如何区分”可以移动”和”不可移动”的对象——这就是值类别体系;然后理解如何在语法层面捕获这种区分——这就是右值引用;最后才是移动操作的具体实现和应用场景。 值类别C++中的每个表达式都有两个独立的属性:类型(type)和值类别(value category)。类型描述表达式的数据结构,值类别则描述表达式的身份和可移动性。 C++11将值类别分为三个基本类别: lvalue(左值)是有持久身份的表达式,可以取地址,例如变量名、解引用表达式、返回左值引用的函数调用: 123456789101112int x = 10;int* ptr = &x;int global = 10;int& getRef() { return global; } // 返回左值引用x = 20; // 变量名是左值*ptr = 30; // 解引用表达式是左值getRe...
C++内存布局与生命周期
C++程序运行时,内存被划分为几个不同的区域,每个区域有不同的分配方式、生命周期和性能特点。理解这些区域的差异,是掌握C++内存管理的基础。 内存区域概览程序中的数据有不同的特点:指令不可修改、全局数据贯穿始终、局部变量随调随销、动态数据大小不定。将它们混在一起管理既不安全也不高效,因此操作系统将内存划分为不同区域,针对各自特点采用最合适的管理策略。 如图所示,从低地址到高地址依次为: 代码段(.text)存放编译后的机器指令,只读且在程序运行期间保持不变,防止程序意外修改自身逻辑。 常量区(.rodata)存放只读数据,包括字符串字面量和const全局常量。编译器可能将相同的字符串字面量合并为一份,尝试修改常量区内容会导致程序崩溃。 数据段存放全局变量和静态变量,生命周期与程序一致。其中.data段存放已初始化的变量,.bss段存放未初始化的变量。 堆是一块较大的内存池,通过new/delete手动管理,向上增长。堆分配的对象不会随函数返回而销毁,必须显式释放。分配速度较慢(需要内存分配算法),频繁分配/释放可能产生碎片。 栈由编译器自动管理,向下增长。函...
C++初始化语法详解
C++提供了多种初始化语法,从C语言继承的传统方式到现代C++引入的统一初始化,每种方式都有其适用场景和特点。理解这些初始化方式的差异,有助于编写更安全、更清晰的代码。 一、声明、定义、初始化与赋值在介绍具体语法前,先区分四个容易混淆的概念。声明(declaration)是告诉编译器变量的类型和名称,不一定分配存储空间,如extern int x;。定义(definition)则为变量分配存储空间,创建变量实体,一个变量只能被定义一次。初始化(initialization)是在定义变量的同时赋予初始值,发生在对象创建的那一刻。赋值(assignment)是对已存在的对象重新设置值,发生在对象创建之后。 12345extern int x; // 声明(不分配空间)int x; // 定义(分配空间,但未初始化)int y = 10; // 定义 + 初始化int z;z = 20; // 赋值,不是初始化(对象已存在) 初始化与赋值的关键区别在于时机。初始化发生在对象创建时,是对象生命周期的起点;赋值发生在对...