2026/4/18 9:05:12
网站建设
项目流程
网站推广工作好做吗,网络组建与配置 2018版清华大学出版社,wordpress 管理文件,a做爰视频免费网站《你真的了解C吗》No.018#xff1a;复制操作的隐式生成规则——“大三原则”的底层逻辑
导言#xff1a;编译器派发的“免费午餐”
为了让类#xff08;Class#xff09;表现得像内置类型#xff08;如 int#xff09;一样方便#xff0c;C 编译器会自动为你的类生成…《你真的了解C吗》No.018复制操作的隐式生成规则——“大三原则”的底层逻辑导言编译器派发的“免费午餐”为了让类Class表现得像内置类型如int一样方便C 编译器会自动为你的类生成四个核心成员函数如果你没有显式声明它们默认构造函数我们在 No.011 聊过。析构函数。拷贝构造函数Copy Constructor。赋值运算符Copy Assignment Operator。本章的重点在于后两者。这些自动生成的函数执行的是“逐成员拷贝Memberwise Copy”这种简单的物理搬运正是无数内存崩溃案的元凶。一、 拷贝生成的底层逻辑位拷贝的局限当你写下Derived d2 d1;时如果Derived没有定义拷贝构造函数编译器会合成一个。合成逻辑它会按照成员在类中声明的顺序依次调用每个成员的拷贝构造函数。内置类型直接进行二进制位拷贝Bitwise Copy。指针类型仅仅拷贝地址数值。这种“浅拷贝”在处理包含int、char等基本类型的类时表现良好但只要你的类中出现了一个指向堆内存的指针这种自动生成的行为就会导致我们在 No.012 中讨论过的双重释放Double Free。二、 “大三原则”Rule of Three的物理依据在 C03 时代这是一条刻在每个开发者骨子里的法则。其核心逻辑是如果你发现类需要处理资源如内存、文件句柄、Socket那么编译器默认生成的行为就不再可靠。原则内容如果你需要显式定义以下三者中的任何一个那么你几乎肯定需要同时定义这三个析构函数因为你有资源需要释放。拷贝构造函数因为你需要确保资源被克隆而非共享。赋值运算符因为你需要先释放旧资源再克隆新资源。三、 隐式生成的“禁区”编译器什么时候会罢工并不是所有情况下编译器都能成功生成这些函数。如果遇到以下情况编译器会拒绝生成默认的复制操作类含有const成员因为常量一旦初始化就不能再被赋值自动生成的赋值运算符无法更改它的值因此编译器会报错。类含有引用成员Reference引用必须在初始化时绑定且不可更改。赋值操作无法改变引用的绑定对象编译器无法替你做决定。成员对象的拷贝操作是私有的Private如果你的类里包含了一个禁止拷贝的对象比如std::ofstream那么你的类也将自动变得不可拷贝。四、 现代视角的审视从隐式到显式虽然我们在讨论 C03但为了理解深度我们需要知道这种“隐式生成”带来的混乱。在后来的 C11 中引入了 default和 delete就是为了打破这种“编译器猜你在想什么”的暧昧状态。在 C03 中如果你想禁止一个类被拷贝你必须使用一个经典的 TrickclassUncopyable{private:// 只声明不定义且设为私有Uncopyable(constUncopyable);Uncopyableoperator(constUncopyable);public:Uncopyable(){}};这样任何尝试拷贝的行为都会在编译期因为 private或链接期因为没有定义报错。总结谁在控制你的对象默认生成是编译器为了方便你而提供的辅助它基于“成员逐一处理”的简单逻辑。大三原则是开发者对编译器能力的边界确认一旦涉及资源所有权必须接管控制权。理解这些规则能让你在看一眼类声明时就预判出它在执行a b时是否会引发灾难。下一篇预告复制操作往往伴随着临时对象的产生。那些在代码行中间一闪而过的“无名氏”它们的寿命到底有多长➡️《你真的了解C吗》No.019临时对象的生命周期——常量的引用绑定与销毁时机。