《Effective C++》读书笔记(二)

WinForm轻松打造AntDesign现代化工具栏 摘要: 本文介绍如何在WinForm中利用AntdUI库实现AntDesign风格工具栏,包括安装配置、动态生成按钮/下拉菜单、布局优化及主题美化。通过AntButton、AntDropdown等控件结合事件绑定,可快速构建支持图标、工具提示、权限控制的现代化工具栏,并解决常见图标加载、布局错乱问题。最后提供代码示例与响应式设计技巧,助你打造高效美观的WinForm界面。 (字数:150) 阅读详情

一.资源管理

资源管理就是我们申请的资源,不管是内存,互斥锁,文件等等,使用过后,都需要归还给系统。C++没有自带的垃圾回收机制,所以自己把握好资源管理是很重要的!

 

13.以对象管理资源:

a)      将一个对象所需要的所有资源放到对象内部,在对象初始化的时候分配资源,并且在对象被销毁的时候将资源释放。

b)      我们通常new一个对象,然后通过指针指向对象,在用过后delete掉。但是有时候会忘记delete,或者在delete前函数return了,这时候,这个指针没了,那这个对象的内存空间就泄露了。对于这种情况,可以使用auto_ptr来解决。

c)      atuo_ptr,智能指针。当auto_ptr被销毁的时候,会自动释放auto_ptr所指向的内容。换句话说,auto_ptr指针指向的内容不需要我们delete,当超出函数作用域,auto_ptr自动销毁,会直接使其所指的对象也销毁。但是auto_ptr的性质决定了其另一个特性,如果auto_ptr进行拷贝或者赋值的话,原来的auto_ptr会被置空。

d)      比auto_ptr更好的为shared_ptr,和auto_ptr用法相同,但是shared_ptr有引用计数机制,当引用计数为0才会清理资源。

e)      auto_ptr的机制比较蛋疼,所以常用的还是shared_ptr。不过注意两者都是进行delete,而不是delete[]操作,所以指向的对象是一个对象,对于一组对象,最好使用vector或者自己DIY一个资源管理类。

 

14.在资源管理类中小心coping行为:

(RAII—Resource Acquisition Is Initialization初始化时获得资源)

如果一个对象中管理了一系列资源,当这个对象被拷贝时,我们就得好好考虑一下了。

a)      禁止复制,这个最简单粗暴,直接拷贝构造函数私有化。

b)      对底层资源采用引用计数法,reference-count

c)      复制底部资源,直接拷贝一份资源给新的资源管理对象。

d)      转移资源拥有权,即原本的资源管理对象管理的资源管理权转移给对象,原本管理权清空。


15.在资源管理类中提供对原始资源的访问:

a)      虽然我们使用资源管理类将资源封装了起来,但是绝大多数的api是不会认得我们自己的资源管理类的,所以,要想使用这个资源,我们必须提供一个对外的接口,换句话说,需要提供资源的原始指针或者引用给外部。

b)      对于这种接口,可以提供显式的接口,比如get()方法,获得原始的指针或引用。而更方便的做法是提供一个隐式转化的函数(实现的话采用operator重载)。两者均可,显式转化比较安全,隐式转化比较方便。

 

16.成对使用new和delete时要采用相同的形式:

这条比较简单,就是new出一个的时候,delete一个,而new出一组的时候,delete也要释放一组。就是当new时使用[]时,delete也要加上[]。

 

17.以独立语句将newed对象置入智能指针:

这个也比较简单干脆。就是先new出来一个对象,然后再把它放入智能指针中,不要把这些操作放在一个语句中,不然,如果中途出现异常,new出来的对象为空,很难察觉。

 

二.设计与声明

针对接口编程,而不是实现编程。所以接口是灰常重要的。我们设计接口的目的为:让接口容易被正确使用,不容易被误用。保证正确性,高效性,封装性,维护性,延展性以及协议的一致性。使用接口容易出错的话,不只是因为用的人不会用,设计接口的人也要负有责任。


18.让接口容易被正确使用,不易被误用:

最简单的,如果一个函数接收一大串参数的话,如果类型不同,也许我们写错位置了编译会报错,如果类型相同,那么,即使写错了位置,编译时也不会报错,运行时就会出现意外的情况。所以个人感觉,能传结构体的还是用结构体传递参数吧,不然实在是太乱了。

关于资源管理的,接口内部是否会涉及到资源的申请以及释放,外部要怎么处理,这也是要注意的。

 

19.设计class犹如设计type:

如果把我们自己写的类当成一个内置的数据类型的话,好像有太多太多的东西我们没有考虑到。比如重载函数和操作符,控制内存分配,对象初始化和终结等。

a)对象如何被创建和释放

b)对象初始化和对象赋值有神马差别

c)如果对象被pass by value了,会发生什么

d)对象内容的合法值范围

e)是否需要考虑继承,如果继承了其他类,虚函数要怎么写,如果要给其他类继承,是否要声明虚函数,尤其是关于虚析构函数。

f)当面对转换类型时应该怎么办

g)什么样的操作符和函数是合理的

h)什么样的函数不应该暴露出去,什么样的系统自动生成的函数应该自己设为private防止暴露。是否需要友元函数

i)是否足够一般化,如果是一个type家族,考虑是否需要用模板

j)是否真的需要重新设计一个类,现有的类是否可以派生出现在的类

 

20.宁以pass-by-reference替换pass-by-value:

a)      通过值传递时,会调用拷贝构造函数构造一个对象的副本,当出了函数的作用域时,又会调用析构函数删除对象,比如一个复杂的对象,内部包含很多字段甚至还包含其他对象,那么,传递这样一个对象简直是灾难。

b)      而且,如果通过值传递参数,如果函数形参是一个基类对象,而实参是一个子类的对象,那么,这样传递进去的参数就会发生切割,即只保留了基类的副本(实参变成了一个基类的对象),而采用pass-by-reference则能够避免这种情况。

c)      pass-by-reference时,一般都是需要使用const关键字限定参数的,即在函数内部不能够对传递进去的参数进行修改。当然,如果需要通过引用来返回结果的话,就不必用const了。

d)      当然,虽然pass-by-reference这么好用,也不是什么时候都要用这个的。当我们要传递的参数是一个内置数据类型时,使用传值可能会效率更高。而且对于STL迭代器和函数对象也是直接传递较好。

 

21.必须返回对象时,别妄想返回其reference:

上面说了,传递参数用reference或者pointer比较好,但是返回的时候,要怎么办,试想一下,一个本地对象,我们返回其reference或者pointer,但是函数结束了,该对象就销毁了,那我们如果再使用这个reference或者pointer,那么程序必崩无疑!!!

看《Effective C++》的作者写了好几个“尝试返回本地reference的反面教材”,有直接返回的,肯定崩;本地new一个再返回的,那么这个对象不会被合理析构,而且如果有连续调用就更麻烦;还有使用static对象的,这样更惨,static对象虽然表面上看起来获得的值不等,但是如果用==判等的话,是必定相等的。

所以,凡事必有两面性,凡事也都有存在的意义。该用什么就用什么,哪个合适就用什么,不要过火。

 

22.将成员变量声明为private:

a)      最直接的就是,如果成员变量为private,那么唯一访问成员变量的接口就是函数,这样可以省去不少麻烦,即所谓的封装。封装最直接的意义就在于可以对变量进行访问控制,比如只读,读写等等。进一步看,有了封装,如果内部成员改变,外部不需要进行改变,减少了耦合性。

b)      封装进一步的保证了“针对接口编程”,同样的一个类,内部存储了一系列属性,但是暴露给外部的接口就是这些,里面可以进行多种实现,为我们提供了灵活性。

c)      再一个灰常有用的地方,当成员变量被修改时,我们可以很容易的知道变量被修改了,因为改变变量的唯一方法就是这个函数,那么只要在这个函数里面动一点手脚就可以了。

d)      如果不进行封装,那些经常变动的东西被外部调用了,那么如果想要修改,就麻烦得多了。

e)      protected类型并没有比public多多少封装性。虽然protected也可以提供封装,但是它对子类是public的,表面上看我们访问不到protected的内容,但是如果它改变了,那它所有的子类也都要遭殃。难怪有人说慎用protected呢!

 

23.宁以non-member&&non-friend替换member函数:

a)      虽然对象中的内容封装起来比较好,但是,对于变量的封装是一部分,而如果需要将多个成员函数一并调用时,再写一个成员函数包含这几个函数,效果却没有非成员函数接受对象,然后在非成员函数中一起调用多个函数效果好。

b)      这里所说的非成员函数指的是非本类的成员函数,可以是全局的函数,不属于任何一个类,也可以是另一个类的成员函数,注意不要是友元函数,友元函数破坏了封装性。

c)      为什么会这样:由于private已经把需要封装的东西封装起来了,暴露出去的接口应该都可以被使用,那么在内部再建立一个包含这些接口的函数并不能更好地再次封装,反而降低了灵活性。

d)      设计了一个类之后,可以用上述的方法,在同一个命名空间中加入一些配合类使用的工具函数,工具函数接受一个类的引用,然后组合调用类的一些方法,这些方法称为便利函数。这些便利函数可以和类在同一个文件中,这样比较方便,可以直接使用。也可以分别位于不同的头文件中,然后使用相同的命名空间即可,这样就可以简单引入一些头文件,而不是全部引入。

 

23.若所有参数都需要类型转换,请为此采用non-number函数:

a)      这个貌似关于运算符重载的时候发生得很多,还是一个例子比较容易看出来问题所在:

比如一个复数类支持*运算符重载,operator* (),我们调用的时候经常是这样用的,obj1 *obj2,但是实际上这个函数是这样调用的obj1.operator*(obj2)。乍一看没有什么问题,但是,如果这样呢obj1.operator*(非该类型的对象),这是,第二个对象会被转化成该对象(前提是支持这种转化),那么操作还是可以进行的。但是,如果反过来,非该类型的对象*obj1,就会变成这样:非该类型的对象.operator*(obj1),那么编译器就会找非该类型的对象是否有operator*操作符,没有的话,找全局操作符,也没有,那么,好的,崩了。

b)      解决这样的问题,就是提供一个non-member函数,因为上面的 obj.operator*(obj)等价于这种operator*(operator1, operator2),用这种函数就可以避免那种类型转换之后,找不到特定函数的特殊情况。其实个人感觉还是这种容易理解,上面那个抽象,而且容易出错。

 

 

24.考虑写出一个不抛异常的swap函数:

Swap函数,本来是stl里面的标准库函数,但是本人貌似基本木有用过。还是看一下这条吧,说实话,服了,这本书的作者真的是C++神级人物。

a)关于swap,简单来说就是交换两个对象(或者原生数据类型)。如果都是对象的话,那么直接赋值就好,但是,如果有指针或者引用的话,就要注意浅拷贝深拷贝的问题。但是,我们正常设计一个类的话,拷贝都设计成深拷贝的。而对于swap,并不需要深拷贝,他只要交换。

b)但是,所以按照深拷贝的方法,那会是新建两个对象,代价很大,最好的办法就是直接交换两个对象中的指针。我们可以考虑自己提供一个对象的swap函数。

c)直接用一个接受两个对象的non-member函数的话,由于要访问私有对象,没有办法实现。所以可以先设计一个member函数,然后用non-member函数调用这个函数。

d)做完这一步,并不算完,因为,你要确保调用swap调用的是我们写的这个版本的,而不是std的。用一个函数,将上面的non-member函数封起来,其中using std::swap。这样,直接调用swap的话,编译器会调用特化最好的swap,因为我们有定义这个函数,所以会调用我们自己写的那个swap,而如果没有这样的swap的话,就调用标准的那个swap,这个是STL里面那个模板定义的,不够特化,所以在有自己的swap时是不会调用这个的。注意调用swap时,不要加任何命名空间前缀。

f)不要对于std添加自定义的东东。

h)这个swap函数是为异常安全提供保障的,它本身绝对不要抛出异常。

基于Abaqus的横向各向同性线弹性理想塑性材料模型的umat子程序实现——以Fortran为例,带您揭秘弹性塑性模型编程之道 通过以上步骤,我们已经在Abaqus中使用Fortran实现了横向各向同性线弹性理想塑性材料模型的umat子程序。在实际应用中,我们需要根据具体的材料特性和加载条件来调整模型参数和计算过程。尽管我在这篇文章中尽力提供了详细的教程,但由于我自身的知识限制和经验不足,可能会有误解或错误。我希望大家在学习过程中能多思考,多实践,多交流,以更好地理解和掌握这个主题。 阅读详情

相关推荐

MRI脑影像分析从哲学到技术:一文搞懂VBM预处理基本原理(全网最详细解析)

   分析大脑解剖学差异最常用方法之一是基于体素的形态学方法(voxel-based morphometry, VBM)。 VBM的基本思想是测量大脑组织,尤其是灰质的局部浓度的差异。在大脑的每个体素处进行操作,然后在两个或多个实验组之间进行统计比较,从而在受调查的组之间建立特定大脑区域中脑组织浓度的统计学显着差异。 VBM分析基于(高分辨率)MRI脑部扫描,涉及大量处理步骤,主要是空间归一化,分割,平滑和统计分析,最终结果是统计图,显示了各组之间组织类型明显不同的区域[^1]。 参考 [^1] ..

意疏的学习笔记 3万+

《effective C++》读书笔记(二)

11. 1)       如果你为class添加一个成员变量(尤其是类成员变量),你必须同时修改copying函数,所有构造函数以及任何非标准形式的operator=。 2)       copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”。在子类中要注意调用基类的构造函数(或copying构造,或operator=等)来完成对基类的操作。 3)

projectoflion123的专栏 363

RTKLIB PPP与RTK_POST精密定位实战:从实时到事后处理的完整流程解析

本文详细解析了如何使用RTKLIB进行精密单点定位(PPP)的完整流程,涵盖从实时处理到事后处理(RTK_POST)的关键步骤。文章深入探讨了数据准备、软件配置、核心参数设置(如电离层、对流层、潮汐改正)以及常见问题排查,旨在帮助用户掌握高精度GNSS定位技术,实现从入门到精通的实战应用。

weixin_29047919的博客 278

Effective C++ | 读书笔记 (二)

第三版第三四章内容

m0_74795952的博客 1080

【ArcGIS风暴】ArcGIS 10.2导入Excel数据X、Y坐标(经纬度、平面坐标),生成Shapefile点数据图层

用过CASS的人都知道,野外数字测图得到的点数据(平面坐标)可以直接导入到CASS中,进一步绘制地形图。那么,带有坐标的数据能不能在ArcGIS中实现点图层的生成呢?答案是必须的! 本文以气象台站shp数据的生成为例,详细介绍ArcGIS 10.2中导入X、Y坐标(这里指的是经度、纬度),生成Shapefile点数据的流程。 相关阅读:《全站仪、RTK测量坐标数据在CASS和ArcGIS中展点的区别和联系》 目录 1、数据准备 2、添加X、Y数据 3、属性表连接(Join) 4、导出为Sh.

智慧空间实验室 10万+

SAP UI5 OData V4 操作结果访问:从 getObject 到返回值上下文与 $$inheritExpandSelect

SAP UI5 OData V4 操作结果获取指南 摘要:在 SAP UI5 OData V4 模型中,操作结果需通过绑定上下文获取而非直接从 invoke() 返回。本文详解核心要点: 数据获取路径 使用 invoke() 发起请求后,通过 getBoundContext().getObject() 获取结果 特定场景下 invoke() 可能返回返回值上下文(如草稿切换) 关键实践技巧 使用 $$inheritExpandSelect 继承字段选择,避免二次读取 对象页应用中,通过替换绑定上下文实现无缝

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 311

Effective C++ 读书笔记(二)

所谓编译单元是指产出单一目标文件的那些源码,包括源码文件和其所包含的头文件。static对象是指其寿命是从被构造出来到程序结束为止。该对象包括global对象、namespace内的对象、文件内、class内、函数内被声明为static的对象。函数内的static对象称为local static对象,其他均为non-local static对象。

qq_53660404的博客 766

基于Cesium实现,动态水面+大坝排水动画

一、绘制面状水域,使用水波纹理,进行渲染,水体透明,可以看到底色。三、使用粒子系统,将喷泉改变方向,加上重力设置,实现排水动画。二、绘制线状三维体,用作模拟大坝拦截效果。四、最后,模拟水位上升,进行淹没分析,

一醉千秋的专栏 1418

《Effective C++》读书笔记二

19、避免返回handles(指针,引用,迭代器)指向对象内部成分 即使函数前面加上const,变成 const Point& upperLeft() const{} 意味着调用者拿到Point引用但是不能涂写,但是让调用者拿到了引用,通过拿到的引用对象调用里面的成员,如果执行这句话时该引用已经不存在(销毁),那么会变成一个空悬、虚吊的对象 20、了解inlining的里...

zhangxiaofan666的博客 243

【CAN总线测试】——通讯相关诊断测试

本章主要介绍通讯相关诊断测试用例设计

LOVE135149的博客 1813

YOLOv11改进策略【Neck】| GSConv+Slim Neck:混合深度可分离卷积和标准卷积的轻量化网络设计

实时检测器架构的轻量级设计GsConv。

Limiiiing的博客 2311

Effective C++ 读书笔记二

条款5:定义好一个空类时,编译器会自动生成无参构造函数、copy构造函数、copy assignment(拷贝赋值)操作符和析构函数 程序员自定义的函数的优先级高于编译器自动生成的,当程序员自己实现了上述函数时,编译器就不会生成默认的函数。但是,当编译器生成的默认函数无法满足你的功能时,就需要程序员自己去定义函数了。 条款6:当不想使用编译器生成的默认函数时,将这些不想使用的默认函数自己声明为private,并且只声明,不实现 如果仅仅声明为private的,且实现了(即使是空实现),类的friend

如沐清风的博客 181

“软开关”硬技术!ZVS和ZCS到底谁更牛?看完这个例子你就懂了!

❌ ZVS 和 ZCS 是万能的?→ 不,它们都有实现条件,谐振参数选不好照样硬拐弯!❌ 只要有谐振就一定ZVS?→ 不,一定要设计合适的死区时间和负载条件才行!ZVS 是让电压先“冷静”,ZCS 是让电流先“退场”。一个是开门不撞墙,一个是关门不甩门。懂了它们,功率设计就是在跳华尔兹而不是打架!💃🔌。

weixin_43199439的博客 1236

Effective C++读书笔记(二)

二、构造/析构/赋值运算 条款05:了解C++默默编写并调用哪些函数 如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数,一个copy assignment操作符和一个析构函数。此外如果你没有声明任何构造函数,编译器也会成为你声明一个默认构造函数。所有这些函数都是public且inline。 惟有当这些函数被需要(被调用),它们才会被编译器创建出来。 注意

u010358881的专栏 396

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Effective C++读书笔记二

二构造/析构/赋值运算 几乎你写的每个class都会有一或多个构造函数、一个析构函数、一个拷贝赋值操作符。如果这些函数犯错,会导致深远且令人不愉快的后果,遍及整个classes。所以确保它们行为正确是生死攸关的大事。 条款05:了解C++默默编写并调用哪些函数 如果你自己没声明,编译器就会为类声明(编译器版本的)一个拷贝构造函数,一个拷贝赋值操作符和一个析构函数。此外如果你没有声明任何构造

小李的专栏 611

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Effective C++ 条款总结 读书笔记(二)

Item Effective C++ 条款 item_20 Avoid data members in the public interface This rule warns you if data members are present in the public interface. Instead of making data members public, you should

聚精会神搞建设 1449

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

effective c++读书笔记(二)

Constructors, Destructors, Assignment operators

VanityLost_CY的博客 328

Effective C++读书笔记(二)

条款5:了解C++默默编写并调用哪些函数 如果打算在一个类中内含引用成员的函数中赋值,必须自己定义一个copy assignment 操作符 如果某个base class将copy assignment 声明为private,则在derived中编译器拒绝为其生成copy assignment操作符,因为derived class 可以调用base class 的copy函数. 条款6:防止使用编...

人总是要有梦想的QAQ的博客 101

《More Effective C++ 》读书笔记(二)Exception 异常

这事篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点。我推荐学C++的人都好好读一遍Effective C++ 系列,真是好书啊,对于学完C++ 基础知识的人,这是本高阶秘籍。 笔记 条款 9 - 15 关注的主题是异常。关注1、异常可能引起的资源泄露(强烈推荐使用智能指针)2、异常是如何抛出的和3、异常的成本。目的...

weixin_30896825的博客 125

effective C++读书笔记(二)

2. 构造/析构/赋值运算(Constructors,Destructors,and Assignment Operators) 条款05: 了解C++ 默默编写并调用哪些函数(Knowwhat functions C++ silently writes and calls) 本条款讲了编译器自动为你创建了哪些函数。 用户定义一个empty class,当C++ 处理过它之后,如果

necrazy的专栏 791

effective C++ 读书笔记(二)

第二章 构造 / 析构 / 赋值函数 条款05:了解C++默默编写并调用哪些函数 n        编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符,以及析构函数 copy构造函数和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每一个non-static成员变量拷贝到目标对象。 条款06:若不想使用编

kindlucy的专栏 697

《More Effective C++》读书笔记-技术(二)

30、proxy classes(代理类)可以用两个类来实现二维数组:Array1D是一个一维数组,而Array2D则是一个Array1D的一维数组。Array1D的实例扮演的是一个在概念上不存在的一维数组,它是一个代理类。代理类最神奇的功能是区分通过operator[]进行的是读操作还是写操作,它的思想是对于operator[]操作,返回的不是真正的对象,而是一个 proxy类,这个代理类记录了对

爱橙子的OK绷的专栏 641

【转】effective C++读书笔记(二)

<br />转自:http://hi.baidu.com/a024014/blog/item/617b690ac43e8b1a95ca6ba2.html<br /> <br />类和函数:设计与声明<br /><br /><br />条款18 :争取使类的接口完整并且最小<br /><br />条款19 :分清成员函数,非成员函数和友元函数<br />如果f 必须是虚函数,就让它成为C 的成员函数。<br />operator>>和operator<<决不能是成员函数。如果f 是operator>>或o

hq0520的专栏 347

More Effective C++读书笔记(二)

1、不要试图重载||,&&操作符,因为它们使用短路求值法(一旦确定了布尔表达式的真假值,即使还有部分表达式没有被测试,布尔表达式也停止运算),而重载之后采用的是函数调用法。首先当函数被调用时,需要运算其所有参数,所以调用函数functions operator&& 和 operator||时,两个参数都需要计算,换言之,没有采用短路计算法。第二是C++语言规范没有定义函数参数的计算顺序,所以没有办

孟源的专栏 1052
上一篇: Lua学习笔记--模块与包
下一篇: .dll,.lib,.def 和 .exp文件
puppet_master
puppet_master 领域专家: C/C++技术领域 领域专家: C/C++技术领域
博客等级 码龄12年 2695粉丝 161原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值