![](https://img-blog.csdnimg.cn/20210129101810834.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
《Effective C++》条款笔记
对E-C的学习笔记
JeffyGao
吃完饭再说 0.0
展开
-
有些场景仍然需要 写成 non-member func进行隐式类型转换(implicit type conversion)
有些场景仍然需要 写成 non-member func进行隐式类型转换(implicit type conversion)《Effective C++》 条款-24:若所有参数皆需类型转换,请为此采用 Non-member func()举例: 写一个 operator*, 然后测试其交换律结论:当在 member func() 中,写成Entity operator* ( const Entity& e) 会造成不能隐式转换的问题;当写成 non-member func()时候,写成Ent原创 2022-05-04 20:14:51 · 800 阅读 · 0 评论 -
探究 return-by-reference 和 return by object的区别
本节探究 return-by-reference 和 return by object的区别做法:写一个class,调用 operator +,来探究其 ctor、dtor结论:Entity& : return by reference 不会在 + 的过程中调用 ctor、dtorEntity : return by value 会在+ 的过程中调用 copy ctor、dtor#include <iostream>class Entity{public:原创 2022-05-04 20:12:18 · 929 阅读 · 0 评论 -
尽量以 pass-by-reference-to-const 替换 pass-by-value
尽量以 pass-by-reference-to-const 替换 pass-by-value本节探索 以&传递参数和 value传递参数的区别结论=>pass-by-reference 不会再调用 ctor 生成对象pass-by-value 会调用 class的 copy cotr 和 dtor#include <iostream>class Entity{public: Entity( ){ std::cout << "ct原创 2022-05-04 20:10:33 · 144 阅读 · 0 评论 -
operator = 为了能够连续使用 = 赋值,所以返回类型为 &,即 reference by this *
eg. Base& operator= ( Base& b ){}【注】系统会有自带的 operaotr =, 所以我在自己写的里面 = 100以示区别#include <iostream>class Base{public: Base( ){ std::cout << "ctor" << std::endl; } Base( int x, int y ) : _x(x), _y(y){ s原创 2022-05-04 20:06:37 · 212 阅读 · 0 评论 -
在多态中,base class中如果有 virtual func(),那基类的 dtor要声明为虚函数
/** * 问题描述: * 在多态中,base class中如果有 virtual func(),那基类的 dtor要声明为虚函数 * */#include <iostream>class Base{public: Base( ){ std::cout << "Base ctor" << std::endl; }// virtual ~Base( ){ ~Base( ){ std::cout原创 2022-05-04 20:04:48 · 184 阅读 · 0 评论 -
不允许类被拷贝、赋值的情况
问题抛出:不允许类被拷贝、赋值每个 class 都是独一无二的,不希望 copy ctor和 assignment很奇怪,我只要不定义 copy(),那么在 main() 中就不能调用了呀?其它方法:将 copy() 放到 privateoperator() = delete;#include <iostream>class Entity{public: Entity( int x, int y ) : _x(x), _y(y) { std::co原创 2022-05-04 20:04:16 · 257 阅读 · 0 评论 -
func()后接 const
效果:class 可以调用 func()、func() const.const class 只能调用 func() const.C++在函数后加const的意义:已定义成const的成员函数,一旦企图修改数据成员的值,则编译器按错误处理。非静态成员函数后面加const (加到非成员函数或静态成员后面会产生编译错误)表示成员函数隐含传入的this指针为const指针,决定了在该成员函数中, ―任意修改它所在的类的成员的操作都是不允许的(因为隐含了对this指针的const引用);唯一的例外是对原创 2022-05-04 20:02:59 · 839 阅读 · 0 评论 -
探究隐式转换 explicit
《Effective C++》 导读探究隐式转换 explicitexplicit:通过将 ctor 声明为explicit,可以阻止它们被用来执行隐式转换(implicit type conveesions),但是它们仍可被用来进行显示类型转换#include <iostream>class A{public: A(){ std::cout << "ctor A()" << std::endl; }};class B原创 2022-05-02 22:04:21 · 839 阅读 · 0 评论 -
探究 size_t的使用
《Effective C++》 导读探究 size_t的使用1:strlen() 返回的是 size_t类型;2:当比较 int和 size_t时,首先会将 Num_a 转化为 size_t类型,又由于它是负数,所以转化后的大于strlen(Str_1)#include <iostream>#include <cstring>int main( ){ int Num_a = -1; char* Str_1 = "hello"; std::cout原创 2022-05-02 22:03:29 · 609 阅读 · 0 评论 -
24 若所有参数皆需类型转换,请为此采用 non-member 函数
条款-24 若所有参数皆需类型转换,请为此采用 non-member 函数Remember:1-如果你需要为某个函数的所有参数(包括被 this 指针所指的哪个隐喻参数)进行类型转换,那么这个函数必须是个 non-member。【注】函数后 + const :表明该函数为 “只读”。函数不可修改 class 成员;函数前 + const:返回值为 const。...原创 2021-02-05 17:53:51 · 124 阅读 · 0 评论 -
23 宁以 non-member、non-friend 替换 member 函数
条款 -23 宁以 non-member、non-friend 替换 member 函数Remember:1-宁可拿 non-member 、 non-friend 函数替换 member 函数。 这样做可以增加封装性、包裹弹性(packaging flexibility)p.s. non-member函数: 不是类的成员(member)函数。通过具体类实现调用eg. (类 A) …… void fun1(A& name1){ name1.a();原创 2021-02-05 17:07:19 · 210 阅读 · 0 评论 -
22 将成员变量声明为 private
条款 - 22 将成员变量声明为 private 如果成员变量不是 public ,客户唯一能够访问对象的办法就是通过成员函数。这也体现了“封装”的思想。 使用函数可以让你对成员变量的处理有更精确的控制。( 如果你令成员变量为 public ,每个人都可以读写它,但如果你以函数取得或设定其值,你就可以实现出 “ 不准访问 ”、“ 只读访问 ”、“ 读写访问 ” )。Remember:1- 切记将成员变量声明为 private。 这可赋予客户访问数据的一致性、可细微划分访问控制、允诺约原创 2021-02-05 16:59:07 · 202 阅读 · 0 评论 -
21 必须返回对象时,别妄想返回其 reference
条款-21 必须返回对象时,别妄想返回其 referenceRemember:1-绝不要返回 pointer 或 reference 指向一个 local stack 对象,或返回 reference 指向一个 heap-allocated 对象,或返回 pointer 或 reference 指向一个 local static 对象而有可能同时需要多个这样的对象。 条款-4 已经为 “在单线程环境中合理返回 reference 指向一个 local static ” 对象提供了一份设计实例。.原创 2021-02-03 10:08:36 · 136 阅读 · 0 评论 -
20 宁以 pass-by-reference-to-const 替换 pass-by-value
条款-20 宁以 pass-by-reference-to-const 替换 pass-by-value总结一句话:在函数形参中 最好是 const + 引用,避免构造和析构带来的时间、空间消耗。Remember:1- 尽量以 pass-by-reference-to-const 替换 pass-by-value。 前者通常比较高效,并可避免切割问题(slicing problem)2- 以上规则并不适用于内置类型,以及 STL 的迭代器和函数对象。 对它们而言 pass-by-value原创 2021-02-03 10:01:57 · 123 阅读 · 0 评论 -
19 设计 class 犹如设计 type
条款-19 设计 class 犹如设计 typeRemember:1- class 的设计就是 type 的设计。 在定义一个新 type 之前,请确定你已经考虑过本条款覆盖的所有讨论主题。几乎每一个 class 都要求你面对以下提问:新 type 的对象应该如何被创建和销毁?对象的初始化和对象的赋值该有什么样的差别?新 type 的对象如果被 passed by value(以值传递),意味着什么?什么是新 type 的“合法值” ?你的新 type 需要配合某个继承图系( in原创 2021-02-03 09:48:49 · 160 阅读 · 0 评论 -
18 让接口容易被正确使用,不易被误用
条款 -18 让接口容易被正确使用,不易被误用Remember:1- 好的接口很容易被正确使用,不容易被误用。你应该在你的所有接口中努力达成这些性质。2- “促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容。3- “阻止误用”的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。4- tr1::shared_ptr 支持定制型删除器(custom deleter)。这可防范 DLL(动态连接程序库) 问题,可被用来自动解除互斥锁(mutexes:条原创 2021-02-03 09:43:27 · 132 阅读 · 0 评论 -
17 以独立语句将 new**ed**对象置入智能指针
条款-17 以独立语句将 newed对象置入智能指针p.s.智能指针通过析构函数释放有它管理的堆内存。Remember:1-以独立语句将 newed 对象存储于(置入)智能指针内。 如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄露。使用分离语句能够有效避免错误://写成下面这样比较好。(其中 A是类, fun1是函数)std::tr1::shared_ptr<A> pw(new A);pA(pw, fun1());//而不是pA(std::tr1::shar原创 2021-02-03 09:31:01 · 109 阅读 · 0 评论 -
16 成对使用 new 和 delete 时要采取相同形式
条款 -16 成对使用 new 和 delete 时要采取相同形式Remember:1-如果你在 new 表达式中使用[] ,必须在相应的 delete 表达式中也使用 []。如果你在 new 表达式中不使用[] ,一定不要在相应的 delete 表达式中使用 []。eg.std::string* str1 = new std::string;std::string* str2 = new std::string[100];……delete str1; //删除一个对象delete[]原创 2021-02-03 09:25:27 · 164 阅读 · 0 评论 -
15 在资源管理类中提供对原始资源的访问
条款-15 在资源管理类中提供对原始资源的访问Remember:1- APIs 往往要求访问原始资源(raw resources),所以每一个 RAII class 应该提供一个“取得其所管理之资源”的办法。2- 对原始资源的访问可能经由显示转换或隐式转换。一般而言显示转换比较安全,但隐式转换对客户比较方便。 许多APIs 直接指涉资源,我们只能绕过资源管理对象(resource-managing objects)直接访问原始资源(raw resources)。(【注】也就是说这些API 只原创 2021-02-03 09:20:49 · 167 阅读 · 0 评论 -
14 在资源管理类中小心 copying 行为
条款-14 在资源管理类中小心 copying 行为Rememebr:1-复制 RAII 对象必须一并复制它所管理的资源,所以资源的 coping 行为决定 RAII 对象的 coping行为。2-普遍而常见的 RAII class coping 行为是:以制 coping、施行引用计数法(reference counting)。不过其它行为也都可能被实现。 像 auto_ptr、shared_ptr 一般用于堆上的资源管理,但是有些资源管理类并不在堆上操作,所以无法用智能指针。 在进行原创 2021-02-02 11:18:03 · 181 阅读 · 0 评论 -
13 以对象管理资源
条款- 13 以对象管理资源Remember:1- 为防止资源泄露,请使用 RAII(资源获取初始化) 对象,它们在构造函数中获得资源并在析构函数中释放资源。2- 两个常被使用的 RAII class 分别是 tr1::shared_ptr 和 auto_ptr。前者通常是较佳选择,因为其 copy 行为比较直观。若选择 auto_ptr,复制动作会使它(被复制物)指向 null。 所谓 资源 就是,一旦使用了它,将来就必须还给系统。C++ 最长用的就是动态分配内存,如果不释放的话,就会造成内原创 2021-02-02 11:09:25 · 118 阅读 · 0 评论 -
12 复制对象时勿忘其每一个成分
条款-12 复制对象时勿忘其每一个成分copy 函数应该确保复制“对象内的所有成员变量”及“所有 base class成分”。不要尝试以某个 copy 函数实现另一个 copy 函数。应该将共同机能放进第三个函数中,并由两个 copy 函数共同调用。...原创 2021-02-02 10:31:59 · 187 阅读 · 0 评论 -
11 在 operator= 中处理“自我赋值”
条款- 11 在 operator= 中处理“自我赋值”确保当对象自我赋值时 operator= 有良好行为。其中技术包括比较“来源对象” 和 “目标对象”的地址、精心周到的语句顺序、以及 copy-and-swap。确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。“自我赋值”很容易被使用,虽然没有意义,但若不加以 处理会造成系统报错。法 1 传统做法:在 operator= 里做一个“证同测试( identity test )”达到“自我赋值”的检测目的。原创 2021-02-01 10:32:12 · 146 阅读 · 0 评论 -
10 令 operator= 返回一个 reference to *this
条款-10 令 operator= 返回一个 reference to *this令赋值(saaignment)操作符返回一个 reference to *this。常量有以下赋值连锁形式:int x, y, z;x = y = z = 15;// x = ( y = (z = 15) )// 15先被赋值给z,然后其结果(更新后的z)再被赋值给y,同理赋值给x。为了实现“连锁赋值”,赋值操作符必须返回一个 reference指向操作符的左侧实参。在 copy assignment操原创 2021-02-01 10:18:24 · 150 阅读 · 0 评论 -
09 绝不在构造和析构过程中调用 virtual 函数
条款-09 绝不在构造和析构过程中调用 virtual 函数在构造和析构期间不要调用 virtual 函数,因为这类调用从不下降至 derived class(比起当前执行构造函数和析构函数那层)原创 2021-02-01 10:12:40 · 112 阅读 · 0 评论 -
08 别让异常逃离析构函数
条款-08 别让异常逃离析构函数析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或者结束程序。如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么 class 应该提供一个普通函数(而非在析构函数中)执行该操作。“吐出异常”:会带来过早地结束程序或发生不明确行为的风险。...原创 2021-02-01 10:03:54 · 134 阅读 · 0 评论 -
07 为多态基类声明 virtual 析构函数
条款-07 为多态基类声明 virtual 析构函数polymorphic (带多态性质的) base class 应该声明一个 virtual 析构函数。如果 class 带有任何 virtual 函数,它就应该拥有一个 virtual 析构函数。class 的设计目的如果不是作为 base class 使用,或不是为了具备多态性( polymorphically ),就不该声明 virtual 析构函数。 任何 class 只要带有 virtual 函数都几乎确定应该也有一个 virtual原创 2021-02-01 09:56:22 · 133 阅读 · 0 评论 -
06 若不想使用编译器自动生成的函数,就该明确拒绝
条款-06 若不想使用编译器自动生成的函数,就该明确拒绝为驳回编译器自动(暗自)提供的机能,可将相应的成员函数声明为 private 并且不予实现。使用像 Uncopyable 这样的 base class 也是一种做法。有 以下两种方法避免编译器自动生成拷贝构造函数:把 cpoy 构造函数和 copy assignment写在基类的 private继承里,且只写声明,不写参数名称。class HomeForSale { public: …… private:原创 2021-02-01 09:32:47 · 264 阅读 · 0 评论 -
05 了解C++ 默默编写并调用哪些函数
条款-05 了解C++ 默默编写并调用哪些函数编译器可以暗自为 class 创建 default 构造函数、copy构造函数、copy assigment操作符,以及析构函数。如果你写下:class Empty();这就好像你写下这样的代码:class Empty(){ public: Empty(){……} // 默认构造函数 ~Empty(){……} // 默认析构函数 Empty( const Empty &rhs){……} // 拷贝构造函数原创 2021-01-31 21:21:51 · 172 阅读 · 0 评论 -
04-确定对象被使用前已被初始化
条款04-确定对象被使用前已被初始化为内置型对象进行手工初始化,因为C++不保证初始化它们。构造函数最好用成员初始值列(member initialization list),而不要在构造函数本体内使用赋值操作(assignment)。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。为免除“跨编译单元之初始化次序”问题,请以local static对象替换 non-local static对象。对指针的初始化:使用 const(在条款-03中有说明,当const在星号左边原创 2021-01-29 12:18:35 · 135 阅读 · 0 评论 -
03-尽可能使用 const
条款03-尽可能使用 const1.char greeting[] = "hello";char *p = greeting; //non-const pointer, non-const dataconst char *p = greeting; //non-const pointer, const datachar* const p = greeting; //const pointer, non-const dataconst char* const p = greet原创 2021-01-29 11:00:54 · 105 阅读 · 0 评论 -
02 尽量以 const、enum、inlinen 替换 #define
条款-02 尽量以 const、enum、inlinen 替换 #define1-对于单纯常量,最好以 const 对象 或 enums 替换 #defines。2-对于形似函数的宏(macros),最好改用 inline 函数替换 #defines。在用**#define**进行预处理时:#define AA 1.653 可能会在记号式调试器(symbolic debugger)中,名称 AA 未进入记号表(symbol table)或者编译器未看见 AA 而产生误差。 解决方法原创 2021-01-29 10:39:35 · 98 阅读 · 0 评论 -
01 让自己习惯C++
条款-01 让自己习惯C++ C++最先只是C加上一些面向对象特性,也就是 C with Classes。 C++现在是一个多重泛型编程语言(multiparadigm programming language),同时支持过程形(procedural)、面向对象形式(object-oriented)、函数形式(functional)、泛型形式(generic)、元编程形式(metaprogramming)的语言。C++可以(理解成)以下四种语言的结合:C:但它比C语言多了模版(templ原创 2021-01-29 10:24:17 · 218 阅读 · 0 评论