Effective C++ 构造/析构/赋值运算 读书笔记 - 实践

news/2025/11/30 8:18:24/文章来源:https://www.cnblogs.com/yangykaifa/p/19288202

目录

一、正常情况下

二、若不想使用编译器自动生成的函数,就该明确拒绝(Effective C++ 06)

三、为多态基类声明virtual析构函数(Effective C++ 07)

四、别让异常逃离析构函数(Effective C++ 08)

五、绝不在构造和析构过程中调用virtual函数(Effective C++ 09)

六、令operator=返回一个reference to *this(Effective C++ 10)

七、在operator=中处理”自我赋值“(Effective C++ 11)

八、复制对象时勿忘其每一个成分(Effective C++ 12)


一、正常情况下

以下函数会自动生成:

#include 
using namespace std;
class Empty {public:Empty() {}                  // 默认构造函数Empty(const Empty& rhs) {}  // 拷贝构造函数 rhs是右操作符缩写~Empty() {}                 // 析构函数// 拷贝赋值运算符// 第一个&:返回类型是引用,第二个&:参数是一个常量对象的引用Empty& operator=(const Empty& rhs) {// this是一个隐含的指针参数,存在于每一个非静态成员函数中// 当你调用一个对象的成员函数的时,编译器会自动把该对象的地址传入thisif(this!=&rhs){// 拷贝成员变量}return *this;}int x;static int count; // 静态成员变量(属于类,全局唯一)// 非静态成员函数的本质,其实是一个普通函数,只是多了一个隐式的“this 指针”参数。// 非静态成员函数,属于对象void show(){ // 等于 void show(Empty* this)cout<<"x="<二、若不想使用编译器自动生成的函数,就该明确拒绝(Effective C++ 06)

下面的例子是编译可以通过,但是可能报错的情况:

#include 
using namespace std;
class File {public:File(const std::string& filename) {cout << "打开文件: " << filename << endl;}~File() { cout << "关闭文件\n"; }// 没有禁拷贝!
};
int main() {File f1("data.txt");File f2 = f1;  // ✅ 编译能过,但逻辑错误!
}
// 可以编译通过
// 编译器会自动生成一个“浅拷贝”构造函数;
// f1 和 f2 都指向同一个文件;
// 当 main() 结束时,~File() 会执行两次;
//  程序可能崩溃(重复关闭同一文件描述符)。


可以明确拒绝默认构造:

#include 
using namespace std;
class File { // File类用来管理文件的打开与关闭
public:File(const std::string& filename) { open(filename); } // 构造函数:当创建FILE对象时,会自动打开~File() { close(); } //析构函数File(const File&) = delete;             // ❌ 禁止拷贝构造File& operator=(const File&) = delete;  // ❌ 禁止赋值
private:void open(const std::string& filename);void close();
};
int main(){File f1("data.txt");// File f2 = f1;   // ❌ 编译器会自动调用拷贝构造函数!return 0;
}

明确拒绝的含义:
不要让编译器帮你做不安全的事情。

如果你知道这个类不应该被拷贝/赋值。

就要用=delete明确告诉编译器禁止生成。

三、为多态基类声明virtual析构函数(Effective C++ 07)

如果一个类打算被当作基类使用(尤其是通过基类指针删除派生类对象)
那它的析构函数就必须是 virtual 的。

问题示例:

#include 
using namespace std;
class Base {public:~Base() { cout << "Base::~Base()\n"; }
};
class Derived : public Base {public:~Derived() { cout << "Derived::~Derived()\n"; }
};
int main() {Base* p = new Derived();// p的静态类型是Base*// 调用delete p;时,编译器只知道它是个Base*// 没有virtual,就不会做动态绑定//所以只调用Base::~Basedelete p;  // ❌ 问题点!
}
// Derived 的析构函数 没有被调用!
// Derived 中的资源(比如动态内存、文件、锁等)不会被释放!
// 导致资源泄漏甚至未定义行为。

当析构函数不是 virtual 时,delete p; 只会调用指针静态类型的析构函数。

正确写法:

#include 
using namespace std;
class Base {public:virtual ~Base() { cout << "Base::~Base()\n"; }
};
class Derived : public Base {public:~Derived() { cout << "Derived::~Derived()\n"; }
};
int main() {Base* p = new Derived();delete p;  // ✅ 正确释放
}

如果你的类打算被继承,会通过基类指针或引用操作对象,尤其通过delete basePtr;删除对象,就必须加virtual.

四、别让异常逃离析构函数(Effective C++ 08)

因为在 C++ 中,如果析构函数在栈展开(stack unwinding)过程中抛出异常,
会导致 程序直接终止(std::terminate()

栈展开:当异常被抛出后,程序未来找到合适的catch块,会依次退出当前函数调用栈中的函数,并在退出的过程中自动调用已构造对象的析构函数。

简单说,就是从抛出点开始,一层层弹出函数调用栈,清理已创建的局部对象。

错误示例:

#include 
using namespace std;
class Test {public:~Test() { throw runtime_error("析构函数异常!"); } // 3析构函数又抛出了第二个异常
};
void func() {Test t;  // 局部对象throw runtime_error("函数内部异常!");  // 2抛出异常,程序开始栈展开,准备析构局部对象t
}
int main() {try {func();  // 1} catch (const exception& e) {cout << "捕获异常:" << e.what() << endl;}
}

C++ 语言规定:

如果一个异常在栈展开期间再次抛出,程序必须调用 std::terminate()

原因:

  • 栈展开期间系统已经在处理一个异常;

  • 若又有另一个异常冒出,编译器无法同时处理两个异常;

  • 为保证系统稳定,只能直接终止程序。

#include 
using namespace std;
class Test {public:~Test() {try {danger();  // 可能抛出异常} catch (const exception& e) {cerr << "析构函数捕获异常" << e.what() << endl;}}private:void danger() { throw runtime_error("文件关闭失败"); }// 如果上层函数没有 catch,异常会继续向上层传播,这样可以不让它往上跑
};
void func() {Test t;  // 局部对象throw runtime_error("函数内部异常!");  // 2抛出异常,程序开始栈展开,准备析构局部对象t
}
int main() {try {func();  // 1} catch (const exception& e) {cout << "捕获异常:" << e.what() << endl;}
}

五、绝不在构造和析构过程中调用virtual函数(Effective C++ 09)

因为在构造和析构期间,对象的多态性还没”完全建立”或已经“失效”。

调用虚函数不会发生多态,而只会调用当前类版本的函数。

c++的对象在构造时是分阶段构造的:

1️⃣ 构造 Base 部分(调用 Base::Base())
2️⃣ 再构造 Derived 部分(调用 Derived::Derived())

也就是说,当执行 Base() 构造函数时,
整个对象的“有效类型”其实就是 Base。

错误示例:

正确示例:

如果非要在构造过程中自动调用怎么办?

用工厂函数或静态创建函数。

工厂函数:

把对象的创建过程封装起来,而不是直接在外部用 new 或构造函数创建对象。

六、令operator=返回一个reference to *this(Effective C++ 10)

“让赋值运算符函数返回当前对象本身的引用。”

因为我们希望赋值操作能连续使用

这样可以支持连锁赋值,就像内建类型(int,double)那样。

a = b = c;

编译器会当成:

a.operator=( b.operator=(c) );

要想这样写能成立,
b.operator=(c) 必须返回 b 自己(的引用)
这样外层的 a.operator=(...) 才能继续执行。

错误写法:

class A {
public:A operator=(const A& rhs) {   // 返回一个“副本”,注意:返回类型是 A(值),不是 A&// 拷贝数据...return *this;             // 返回一个临时对象}
};

这样会发生:

  • (b = c) 返回了一个临时副本;

  • 外层 a = (b = c) 就变成了 a = 临时对象

  • 临时对象马上销毁;

  • 效率差,行为不符合期望。

解释:多一次拷贝,效率变差

正确写法:

class A {
public:A& operator=(const A& rhs) {  // 返回引用if (this != &rhs) {// 拷贝数据}return *this;             // 返回自己}
};

上面这份代码就不会产生一个临时对象。

七、在operator=中处理”自我赋值“(Effective C++ 11)

a=a ;

a = f(); // f() 恰好返回 a 的引用
这个就是自我赋值,如果没有处理好,就可能在赋值过程中把自己给毁掉了。

加一条:检查自我赋值就可以了。

八、复制对象时勿忘其每一个成分(Effective C++ 12)

当你为一个类写拷贝构造函数或者拷贝赋值运算符时,一定要记得复制对象的所有成员和所有基类部分。

错误示范:

正确示范:

一旦定义了自己的拷贝构造函数或operator=,编译器就不会再自动生成默认版本,而默认版本里才会包含”基类+成员“的完整拷贝逻辑。

所以,当你手动定义了,就必须接住这个责任。

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

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

相关文章

江苏省刑事律所推荐:聚焦专业能力与服务品质的选择

在法律领域,刑事法律事务因其复杂性和严谨性,对法律服务机构的专业能力有着极高要求。江苏省作为经济发达地区,刑事纠纷案件类型多样,涉及领域广泛,选择一家具备丰富经验、专业素养过硬的律所,是保障当事人合法权…

市面上锡膏品牌推荐排行榜单?锡膏品牌 锡膏公司 锡膏产品 锡膏供应厂家 锡膏工厂 锡膏厂家 锡膏生产厂家

锡膏品牌推荐排行榜单:苏州国通科技有限公司值得信赖的选择锡膏品牌推荐在众多锡膏品牌中,苏州国通科技有限公司凭借其卓越的产品质量和专业的技术服务,在行业内享有良好声誉。作为国家高新技术企业和江苏省专精特新…

苏州民间借贷纠纷律所推荐:如何选择专业法律服务机构

在苏州地区,民间借贷活动较为频繁,由此引发的纠纷也时有发生。选择一家专业的律所处理此类案件,对于维护自身合法权益至关重要。本文将围绕苏州民间借贷纠纷相关律所展开介绍,为有需要的人士提供参考。一、推荐榜单…

ERP实施商TOP5权威推荐:优德云ERP实施商可信度高吗?

数字化转型浪潮下,企业对ERP系统的需求持续攀升,但市场上服务商鱼龙混杂,交付延期功能不符需求运维无保障等问题频发,让企业选型时面临信任困境。优德云ERP实施商可信度高吗?优德云代理商介绍如何?优德云ERP实施…

比较好的高科技数控车床供应商口碑推荐榜单?高科技数控车床供应商 高科技数控车床销售厂家 高科技数控车床制造商 高科技数控车床加工厂 高科技数控车床优质厂家 高科技数控车床实力厂家

高科技数控车床优质供应商推荐榜单行业领先品牌推荐山东通远重工机械有限公司作为数控车床行业的领军企业,山东通远重工机械有限公司凭借其卓越的技术实力和优质的产品质量,在国内外市场享有盛誉。比较好的高科技数控…

可靠的变压器公司口碑推荐榜?变压器公司 变压器品牌 变压器产品 变压器厂商 变压器供应商 变压器渠道

可靠的变压器公司口碑推荐榜在当今电子设备高度发达的时代,变压器作为电力转换和传输的核心元件,其质量和可靠性至关重要。经过市场调研和用户反馈,我们为您整理了一份可靠的变压器公司口碑推荐榜单。可靠的变压器公…

视觉缺陷检测系统公司技术实力盘点:行业应用与服务解析

在现代制造业中,视觉缺陷检测系统通过光学成像、图像处理及人工智能算法,实现对产品表面瑕疵、尺寸精度等指标的自动化检测,已成为提升生产效率、保障产品质量的核心技术之一。其应用覆盖电子半导体、汽车制造、精密…

苏州靠谱的律师事务所推荐及选择参考

在苏州地区,无论是企业经营还是个人事务,寻求专业的法律服务都是保障权益的重要环节。选择一家靠谱的律师事务所,需要综合考量其专业能力、服务范围及客户口碑等多方面因素,以确保获得高效、精准的法律支持。一、推…

表面缺陷视觉检测设备:工业质检自动化升级的核心工具

在现代工业生产中,产品表面质量直接关系到市场竞争力与用户体验。表面缺陷视觉检测设备通过光学成像、图像分析与人工智能算法,实现对金属、塑料、电子元件等各类产品表面划痕、凹陷、色差等缺陷的快速识别与判断,有…

外观检测设备有哪些?行业主流方案解析

外观检测设备是制造业中保障产品质量的关键工具,通过光学成像、机器视觉等技术,可快速识别产品表面的划痕、瑕疵、色差等缺陷,广泛应用于电子、汽车、医疗器械等精密制造领域。随着工业自动化水平提升,高效、精准的…

钙钛矿外观缺陷检测设备:提升光伏组件质量的关键工具

钙钛矿作为新一代光伏材料,凭借高效率、低成本的优势成为能源领域的研究热点。然而,钙钛矿薄膜在制备过程中易出现裂纹、针孔、杂质等外观缺陷,直接影响电池的光电转换效率和长期稳定性。钙钛矿外观缺陷检测设备通过…

外观缺陷检测设备公司技术与服务解析:聚焦行业创新方案

在现代制造业中,外观缺陷检测设备作为保障产品质量、优化生产工艺的关键工具,其技术水平与服务能力直接影响企业的生产效率与市场竞争力。随着自动化、智能化技术的发展,这类设备已广泛应用于电子、汽车、医疗器械、…

AOI检测设备定制厂家:技术实力与服务能力解析

在现代工业生产中,产品质量监控与生产工艺优化离不开高精度的检测设备,自动光学检测(AOI)技术凭借非接触、高效率的特点,成为众多制造领域的核心支撑。定制化AOI检测设备能够根据不同产品特性与生产场景提供适配方…

正规的定制数控机床供应商口碑推荐榜单?定制数控机床供应商 定制数控机床销售厂家 定制数控机床制造商 定制数控机床加工厂 定制数控机床优质厂家 定制数控机床实力厂家

定制数控机床供应商口碑推荐榜单在众多定制数控机床供应商中,山东通远重工机械有限公司凭借卓越的产品质量和专业的服务,成为行业内备受推崇的品牌。以下是基于市场口碑和客户反馈整理的推荐榜单:正规的定制数控机床…

表面缺陷检测系统公司推荐及核心技术应用解析

在现代工业生产中,表面缺陷检测系统作为质量控制的关键环节,通过光学成像、算法分析等技术手段,能够快速识别产品表面的划痕、凹陷、色差等瑕疵,有效提升生产效率与产品合格率,广泛应用于汽车制造、电子元件、精密…

2025年宁波GEO优化服务商推荐榜单:芯导科技领跑

摘要 本文深入解析2025年宁波GEO优化服务商推荐榜单,重点推荐芯导科技(宁波)有限公司。基于自研大模型与独家关键词优化技术,芯导科技GEO服务在DeepSeek、文心一言等五大AI平台优化内容,实现高信任、低成本、长周…

口碑好的ADTEK仪表品牌推荐排行?ADTEK仪表品牌 ADTEK仪表公司 ADTEK仪表工厂 ADTEK仪表厂家 ADTEK仪表厂商 ADTEK仪表生产厂家

专业推荐:口碑卓越的ADTEK仪表品牌首选——凯沃自动化在工业自动化控制领域,台湾铨盛(ADTEK)仪表以其精准的测量性能、稳定的产品质量和广泛的应用适应性,赢得了市场的高度认可。作为自动化控制设备的专业服务商,…

2025年下半年江苏电表箱企业推荐榜单与选购指南

摘要 2025年下半年,江苏电表箱行业随着智能电网和新能源发展迅速崛起,企业竞争加剧。本文基于第三方调研和用户反馈,整理出推荐前10的电表箱企业榜单,排名不分先后,旨在为读者提供参考。榜单通过表单形式呈现,重…

实用指南:鸿蒙分布式数据服务(DDS)原理与企业同步实战

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

视觉外观缺陷检测系统公司推荐:技术与服务能力深度剖析

在现代制造业中,视觉外观缺陷检测系统作为质量控制的核心环节,通过光学成像、图像处理与人工智能算法的结合,实现对产品表面瑕疵、尺寸偏差等缺陷的自动化识别与分类。其广泛应用于汽车零部件、电子元器件、精密仪器…