![](https://img-blog.csdnimg.cn/20201014180756927.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Effective C++(第三版)
文章平均质量分 79
吃着火锅x唱着歌
这个作者很懒,什么都没留下…
展开
-
Effective C++ 学习笔记 条款26 尽可能延后变量定义式的出现时间
因此除非(1)你知道赋值成本比“构造+析构”成本低,(2)你正在处理代码中效率高度敏感(performance-sensitive)的部分,否则你应该使用做法B。你不只应该延后变量的定义,直到非得使用该变量的前一刻为止,甚至应该尝试延后这份定义直到能够给它初值实参为止。如果这样,不仅能够避免构造(和析构)非必要对象,还可以避免无意义的default构造行为。只要你定义了一个变量而其类型带有一个构造函数或析构函数,那么当程序的控制流(control flow)到达这个变量定义式时,你便得承受构造成本;原创 2024-03-12 23:01:13 · 460 阅读 · 0 评论 -
Effective C++ 学习笔记 条款25 考虑写出一个不抛异常的swap函数
因此当你写下一个自定版本的swap,往往提供的不只是高效置换对象值的办法,而且不抛出异常(因为调用的是成员版的swap)。不幸的是有一个理由使你应该为class特化std::swap(很快会描述它),所以如果你想让你的“class专属版”swap在尽可能多的语境下被调用,你需得同时在该class所在命名空间内写一个non-member版本以及一个std::swap特化版本。首先,如果swap的缺省实现码对你的class或class template提供可接受的效率,你不需要额外做任何事。原创 2024-03-12 21:40:09 · 697 阅读 · 0 评论 -
Effective C++ 学习笔记 条款24 若所有参数皆需类型转换,请为此采用non-member函数
地位相当于“被调用之成员函数所隶属的那个对象”——即this对象——的那个隐喻参数,绝不是隐式转换的合格参与者(即oneHalf的operator*只有一个参数,它有一个隐喻参数,就是oneHalf对象自己,它自己是不能从2转换为Rational对象的,意思就是第一个参数是int时不能转换为Rational对象)。太多C++程序员假设,如果一个“与某class相关”的函数不该成为一个member(也许由于其所有实参都需要类型转换,例如先前的Rational的。函数的class的对象,所以编译器调用该函数。原创 2024-03-11 22:46:47 · 566 阅读 · 0 评论 -
Effective C++ 学习笔记 条款23 宁以non-member、non-friend替换member函数
如果你要在一个member函数(它不只可以访问class内的private数据,也可以取用private函数、enums、typedefs等等)和一个non-member non-friend函数(它无法访问上述任何东西)之间做抉择,而且两者提供相同机能,那么,导致较大封装性的是non-member non-friend函数,因为它并不增加“能够访问class内之private成分”的函数数量。面向对象守则要求,数据以及操作数据的那些函数应该被捆绑在一块,这意味它建议member函数是较好的选择。原创 2024-03-11 20:40:42 · 639 阅读 · 0 评论 -
Effective C++ 学习笔记 条款22 将成员变量声明为private
因此,protected成员变量就像public变量一样缺乏封装性,因为在这两种情况下,如果成员变量被改变,都会有不可预知的大量代码受到破坏。如果你对客户隐藏成员变量(也就是封装它们),你可以确保class的约束条件总是会获得维护,因为只有成员函数可以影响它们。重点是,由于通过成员函数来访问平均值(也就是封装了它),你得以替换不同的实现方式(以及其他你可能想到的东西),客户最多只需重新编译(如果遵循条款31所描述的技术,你甚至可以消除重新编译的不便性)。你甚至可以实现“唯写访问”,如果你想要的话:。原创 2024-03-10 17:54:21 · 959 阅读 · 0 评论 -
Effective C++ 学习笔记 条款21 必须返回对象时,别妄想返回其reference
面对现实吧,这个做法不会成功的。因此,这个版本的operator*并未返回reference指向某个Rational,它返回的reference指向一个“从前的”Rational:一个旧时的Rational;内的static Rational对象值”比较,如果比较结果不相等,那才奇怪呢(译注:这里补充说明,两次operator*调用的确各自改变了static Rational对象值,但由于它们返回的都是reference,因此调用端看到的永远是static Rational对象的“现值”)。原创 2024-03-10 16:58:09 · 658 阅读 · 0 评论 -
Effective C++ 学习笔记 条款20 宁以pass-by-reference替换pass-by-value
对内置类型而言,当你有机会选择采用pass-by-value或pass-by-reference-to-const时,选择pass-by-value并非没有道理。当一个derived class对象以by value方式传递并被视为一个base class对象,base class的copy构造函数会被调用,而“造成此对象的行为像个derived对象”的那些特质全被切割掉了,仅仅留下一个base class对象。这是个不可靠的推论。这是正确且值得拥有的行为,毕竟你希望你的所有对象都能够被确实地构造和析构。原创 2024-03-09 15:59:05 · 950 阅读 · 0 评论 -
Effective C++ 学习笔记 条款19 设计class犹如设计type
它也影响函数抛出的异常、以及(极少被使用的)函数异常明细列(exception specifications,也称异常规范,它通过将关键字throw放在函数声明中来指定函数可以抛出的异常,但现代C++编程中,通常不建议使用异常规范,而是通过文档或注释来说明函数可能抛出的异常类型,然后在调用函数时进行适当的异常处理)。如果你继承自某些既有的class,你就受到那些class的设计的束缚,特别是受到“它们的函数是virtual或non-virtual”的影响(见条款36和36)。9.谁该取用新type的成员。原创 2024-03-09 13:33:40 · 379 阅读 · 0 评论 -
Effective C++ 学习笔记 条款18 让接口容易被正确使用,不易被误用
Boost的shared_ptr是原始指针的两倍大,以动态分配内存作为簿记用途和“删除器之专属数据”,以virtual形式调用删除器(假如是一个指向派生类的基类指针,也能正确删除所指对象),并在多线程程序修改引用计数时蒙受线程同步化(thread synchronization)的额外开销(只要程序员定义一个预处理器符号就可以关闭多线程支持)。tr1::shared_ptr没有这个问题,因为它缺省的删除器是来自“tr1::shared_ptr诞生所在的那个DLL”的delete。限制上例类型的值是合理的。原创 2024-03-08 21:26:21 · 731 阅读 · 0 评论 -
Effective C++ 学习笔记 条款17 以独立语句将newed对象置入智能指针
可以确定的是“new Widget”一定执行于tr1::shared_ptr构造函数被调用之前,因为这个表达式的结果还要被传递作为tr1::shared_ptr构造函数的一个实参,但对priority的调用则可以排在第一或第二或第三执行。在上述修订后的代码内,“new Widget”表达式以及“对tr1::shared_ptr构造函数的调用”这两个动作,和“对priority的调用”是分隔开来的,位于不同语句内,所以编译器不得在它们之间任意选择执行次序。2.调用tr1::shared_ptr构造函数。原创 2024-03-07 17:52:15 · 302 阅读 · 0 评论 -
Effective C++ 学习笔记 条款16 成对使用new和delete时要采取相同形式
当你使用delete,也有两件事发生:针对此内存会有一个(或更多)析构函数被调用,然后内存才被释放(通过名为operator delete的函数,见条款51)。单一对象的内存则没有这笔记录。假设内存布局如上,delete灰度区若干内存并将它解释为“数组大小”,然后开始多次调用析构函数,浑然不知它所处理的那块内存不但不是个数组,并且或许那块内存中并未存有它正忙着销毁的那种类型的对象。至少,stringArray所含的100个string对象中的99个不太可能被适当删除,因为它们的析构函数很可能没被调用。原创 2024-03-07 16:45:34 · 574 阅读 · 0 评论 -
Effective C++ 学习笔记 条款15 在资源管理类中提供对原始资源的访问
是否该提供一个显式转换函数(例如get成员函数)将RAII class转换为其底部资源,或是应该提供隐式转换,答案主要取决于RAII class被设计执行的特定工作,以及它被使用的情况。假设有大量与字体相关的C API,它们处理的是FontHandle,那么“将Font对象转换为FontHandle”会是一种很频繁的需求。某些程序员可能会认为,这样到处要求显式转换,让人倒尽胃口,不愿再使用这个class,从而增加了泄露字体的可能性,而Font clsss的主要设计目的就是为了防止资源(字体)泄漏。原创 2024-03-07 13:57:42 · 642 阅读 · 0 评论 -
Effective C++ 学习笔记 条款14 在资源管理类中小心copying行为
幸运的是tr1::shared_ptr允许指定所谓的“删除器”(deleter),那是一个函数或函数对象(function object),当引用次数为0时便被调用(此机能并不存在于auto_ptr——它总是将其指针删除)。即,复制资源管理对象时,进行的是“深度拷贝”。原创 2024-03-06 19:01:03 · 603 阅读 · 0 评论 -
Effective C++ 学习笔记 条款13 以对象管理资源
你或许会惊讶地发现,并没有特别针对“C++动态分配数组”而设计的类似auto_ptr或tr1::shared_ptr那样的东西,甚至TR1中也没有。作为最后批注,必须指出,createInvestment返回的“未加工指针”(raw pointer)简直是对资源泄露的一个死亡邀约,因为调用者极易在这个指针身上忘记调用delete(即使他们使用auto_ptr或tr1::shared_ptr来执行delete,他们首先必须记得将createInvestment的返回值存储于智能指针对象内)。原创 2024-03-06 16:07:25 · 1054 阅读 · 0 评论 -
Effective C++ 学习笔记 条款12 复制对象时勿忘其每一个成分
PriorityCustomer的copying函数看起来好像复制了PriorityCustomer内的每一样东西,但实际上,它只复制了PriorityCustomer声明的成员变量,但每个PriorityCustomer还内含它所继承的Customer成员变量,而那些成员变量却未被复制。如果你发现你的copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,建立一个新的成员函数给两者调用。如果你声明自己的copying函数,意思就是告诉编译器你不喜欢缺省实现中的某些行为。原创 2024-03-06 14:39:11 · 803 阅读 · 0 评论 -
Effective C++ 学习笔记 条款11 在operator=中处理“自我赋值”
这些并不明显的自我赋值,是“别名”(aliasing)带来的结果:所谓“别名”就是“有一个以上的方法指称(指涉)某对象”。稍早作者曾经提过,前一版operator=不仅不具备“自我赋值安全性”,也不具备“异常安全性”,这个新版本仍不具备“异常安全性”。令人高兴的是,让operator=具备“异常安全性”往往自动获得“自我赋值安全”的回报。因为这项测试也需要成本。在operator=函数内手工排列语句(确保代码不但“异常安全”而且“自我赋值安全”)的一个替代方案是,使用所谓的copy and swap技术。原创 2024-03-05 15:42:17 · 287 阅读 · 0 评论 -
Effective C++ 学习笔记 条款10 令operator=返回一个reference to *this
注意,这只是个协议,并无强制性。然而这份协议被所有内置类型和标准程序库提供的类型如string、vector、conplex、tr1::shared_ptr或即将提供的类型(见条款54)共同遵守。因此除非你有一个标新立异的好理由,不然还是随众吧。为了实现“连续赋值”,赋值操作符必须返回一个reference指向操作符的左侧实参。这里15先被赋值给z,然后其结果(更新后的z)再被赋值给y,然后其结果(更新后的y)再被赋值给x。令赋值(assignment)操作符返回一个reference to *this。原创 2024-03-05 14:28:15 · 164 阅读 · 0 评论 -
Effective C++ 学习笔记 条款09 绝不在构造和析构过程中调用virtual函数
那是每一个C++次成分(见条款1)的态度,而这样的对待是合理的:这个对象内的“BuyTransaction专属成分”尚未被初始化,所以面对它们,最安全的做法是视它们不存在。取而代之的是,对象的行为就像base类型的一样。然而如果logTransaction是个正常的(也就是impure)virtual函数并在Transaction内带有一份实现代码,该版本就会被调用,而程序也会继续向前行,留下你百思不解为什么建立一个derived class对象时会调用错误版本的logTransaction。原创 2024-03-05 14:12:44 · 846 阅读 · 0 评论 -
Effective C++ 学习笔记 条款08 别让异常逃离析构函数
如果真有错误发生——如果close的确抛出异常——而且DBConn吞下该异常或结束程序,客户没有立场抱怨,毕竟他们曾有机会第一手处理问题,而他们选择了放弃。容器或array并非遇上麻烦的必要条件,只要析构函数吐出异常,即使并非使用容器或arrays,程序也可能过早结束或出现不明确行为。但如果该调用导致异常,DBConn析构函数会传播该异常,也就是允许它离开这个析构函数,就会造成问题。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕获任何异常,然后吞下它们(不传播)或结束程序。原创 2024-03-04 18:22:36 · 689 阅读 · 0 评论 -
Effective C++ 学习笔记 条款07 为多态基类声明virtual析构函数
这是有问题的,因为C++明白指出,当derived class对象经由一个base class的指针被删除,而该base class带着一个non-virtual析构函数时,其结果未定义——实际执行时通常发生的是对象的derived成分没被销毁。它是一个空的结构体,通常用于迭代器的分类和特性判断)(条款47),它们并非被设计用来“经由base class接口处置derived class对象”,因此它们不需要virtual析构函数。每一个带有virtual函数的class都有一个相应的vtbl。原创 2024-03-04 17:13:42 · 804 阅读 · 0 评论 -
Effective C++ 学习笔记 条款06 若不想使用编译器自动生成的函数,就应该明确拒绝
如想阻止拷贝,但编译器为类声明了拷贝构造函数和拷贝赋值运算符,这样就不能达到目的了。你可以通过将拷贝构造函数和拷贝赋值运算符声明为private的来阻止拷贝。但类的成员函数和友元还可以调用,此时将它们声明但不定义就行了,这样调用它的函数会产生链接错误。C++11中直接将拷贝成员声明为delete的即可。...原创 2020-05-14 16:35:38 · 125 阅读 · 0 评论 -
Effective C++ 学习笔记 条款05 了解C++默默编写并调用了哪些函数
当写下一个空类时,编译器会为你合成一个拷贝构造函数、一个拷贝赋值运算符、一个析构函数,如没有声明其他的构造函数,编译器会合成一个默认构造函数。这些都是inline的public成员。当类有一个引用成员或const成员时,编译器不会合成拷贝赋值运算符。如某个基类将拷贝赋值运算符声明为private的,则编译器不会为派生类合成拷贝赋值运算符,因为派生类无法处理基类的成分。C++11中当没有定义任何拷贝控制成员且所有成员都能移动时,会合成移动构造函数和移动赋值运算符。...原创 2020-05-13 23:58:45 · 123 阅读 · 0 评论 -
Effective C++ 学习笔记 条款04 确定对象被使用前已先被初始化
读取未初始化的值会导致不明确行为。某些平台上读取未初始化的值就会使程序终止运行。永远在使用对象前对其进行初始化。构造函数中用=是赋值,而构造函数初始化列表中是初始化。使用构造函数初始化列表效率较高,因为在初始化后又进行了赋值操作。构造函数初始化列表中也能使用默认构造函数。总是在构造函数初始化列表中列出所有成员变量,虽然类类型的变量会使用默认构造函数初始化,但写出来以避免还得记住哪些成员变量不需显式初始化。内置类型变量的赋值和初始化成本相当,但最好也在构造函数初始化列表中列出,因为const的或引用必原创 2020-05-12 17:45:51 · 167 阅读 · 0 评论 -
Effective C++ 学习笔记 条款03 尽可能使用const
只要某值会保持不变,就应该说出来,即定义为const的。const int *pi = nullptr;int const *pi = nullptr; //两者等价STL的迭代器就像T*指针,将迭代器声明为const的表示一个const指针,即T *const。如果想表示迭代器指向的东西不可被改动,应使用const_iterator。const返回值用于有理数乘法:class Rational { /* ... */ };const Rational operator*(const R原创 2020-05-11 15:38:16 · 134 阅读 · 0 评论 -
Effective C++ 学习笔记 条款02 尽量以const、enum、inline替换#define
宁可以编译器替换预处理器。因为或许#define不被视为语言的一部分,当你:#define ASPECT_RATIO 1.653名字ASPECT_RATIO从未被编译器看到,可能在编译器处理源码前它就被预处理器移走了,于是ASPECT_RATIO可能没进入记号表(symbol table)内,当运用此常量获得一个编译错误时,会带来困惑,因为错误信息可能会提到1.653而不是ASPECT_RATIO。当这个名字被定义在并非你写的头文件内时,会因为追踪它而浪费时间。解决方法:const double原创 2020-05-10 13:21:15 · 160 阅读 · 0 评论 -
Effective C++ 学习笔记 条款01 视C++为一个语言联邦
一开始,C++只是C加上面向对象特性。今天C++是个多重范型编程语言,同时支持过程形式、面向对象形式、函数形式、泛型形式、元编程形式。我们可以将C++看做多个次语言组成的联邦。主要的次语言有:1.C。C++的基础。2.Object-oriented C++。即C whit class。3.Template C++。泛型编程部分,它带来新的编程范型,就是template metaprogramming,TMP模板元编程。4.STL。是个template程序库。在次语言C中,传值通常比传引用高效,但原创 2020-05-09 16:31:35 · 489 阅读 · 0 评论