【C++11】Cyber骇客的覆写协议与基因锁 ——【C++11 新增的类的功能】C++11中新增的类的功能有哪些?有什么变化?此文助你破局!!!
/// SYSTEM READY ///
🌊 🌉 🌊 心手合一 · 水到渠成
| >>> ACCESS TERMINAL <<< | |
| [ 🦾 作者主页 ] | [ 🔥 C++初阶 ] |
| [ 💾C++进阶 ] | [ 📡 代码仓库 ] |
Running Process: 100% | Latency: 0ms
索引与导读
- 前言
- 一、默认的移动操作在做什么?
- 二、编译器何时会自动生成?
- 三、触发与被抑制
- 3.1)完美触发自动生成
- 3.2)自动生成被抑制(退化为拷贝)
- 四、如何显式控制:`= default` 和 `= delete`
- 💻结尾— 核心连接协议
前言
C++11为类引入了多项强力特性(using =default/delete),其次,引入了委派构造函数与继承构造函数,有效减少了重复代码。同时,final与override关键字增强了虚函数重写的类型安全。最后,右值引用与移动构造/赋值的引入,配合nullptr的使用,显著优化了资源管理性能并消除了指针歧义
一、默认的移动操作在做什么?
如果你没有自己写,并且编译器决定为你生成这两个函数,它们的行为逻辑被称为**“按成员移动 (Member-wise Move)”**。
1.默认移动构造函数T(T&& other)2.默认移动赋值运算符T& operator=(T&& other)
它们的具体执行动作取决于类中每个成员变量的类型:
对于内置类型(如
int,char, 指针等):直接进行按位拷贝(浅拷贝)。因为它们没有所谓的“移动”概念。对于自定义类类型成员(如
std::string,std::vector):编译器会尝试调用这些成员自己的移动构造函数/移动赋值运算符。如果该成员不支持移动,则退化为调用它的拷贝构造函数/拷贝赋值运算符。
简单来说:编译器生成的默认版本,就是尽最大努力把你类里所有的成员变量都“移动”一遍
二、编译器何时会自动生成?
❗与默认的拷贝构造函数不同,默认移动函数的生成条件非常苛刻
编译器只有在你没有手动干预类的任何资源管理时,才会大方地为你生成默认移动操作。
- 具体规则如下(又被称为“五法则”的衍生推论):
如果你的类中显式声明了以下任何一个函数,编译器就绝对不会自动生成默认的移动构造函数和移动赋值运算符:
- 析构函数(
~T()) - 拷贝构造函数(
T(const T&)) - 拷贝赋值运算符(
operator=(const T&)) - 移动构造函数(显式声明了移动构造,就不会自动生成移动赋值)
- 移动赋值运算符(显式声明了移动赋值,就不会自动生成移动构造)
编译器的潜台词是:“如果你自己写了析构函数或者拷贝函数,说明你的类里面肯定有需要手动管理的复杂资源(比如裸指针
new出来的内存)
如果我自作主张给你生成一个默认的移动函数(按成员浅拷贝裸指针),大概率会导致多个指针指向同一块内存,最终导致 **Double Free(重复释放内存)**导致程序崩溃。”
三、触发与被抑制
3.1)完美触发自动生成
如果你的类完全由标准库容器或智能指针组成,什么都不用写,享受零成本抽象:
#include<iostream>#include<string>#include<vector>usingnamespacestd;classUser{public:string name;vector<int>data;// 没有写析构函数、拷贝函数};intmain(){User u1{"Alice",{1,2,3}};// 编译器自动生成了移动构造,u1 的字符串和 vector 的底层内存被直接转移给 u2User u2=move(u1);cout<<u1.name.length()<<endl;// 输出 0,u1 被掏空了return0;}3.2)自动生成被抑制(退化为拷贝)
只要你加了一个析构函数,移动语义就会默默失效:
#include<iostream>#include<string>usingnamespacestd;classUser{public:string name;~User(){}};intmain(){User u1{"Bob"};// 因为有自定义析构函数,编译器没有生成默认移动构造。// 这里虽然用了 std::move,但最终会退化调用拷贝构造函数!// 发生了深拷贝,性能下降。User u2=move(u1);return0;}四、如何显式控制:= default和= delete
在C++11及其后续版本中,default关键字用于显式地要求编译器生成默认版本的成员函数
如果你写了析构函数,但你依然确信你的成员变量都可以安全地被默认移动,你可以强制编译器生成它们:
classUser{public:string name;vector<int>data;virtual~User(){}// 抑制了默认移动的生成// 强制编译器生成默认的移动操作!User(User&&)=default;User&operator=(User&&)=default;// 既然显式声明了移动,拷贝操作会被抑制,最好也 default 出来User(constUser&)=default;User&operator=(constUser&)=default;};相反,如果你想彻底禁止别人移动你的对象,可以使用= delete:
classNonMovable{public:NonMovable(NonMovable&&)=delete;// 禁用移动构造};💻结尾— 核心连接协议
警告:🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠
【📡】 建立深度链接:关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。
【⚡】 能量过载分发:执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。
【💾】 离线缓存核心:将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。
【💬】 协议加密解密:在评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。
【🛰️】 信号频率投票:通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。
