Effective C++ 第二版

随笔分类 - effective c++

【effective c++】构造/析构/赋值运算

摘要:条款5:了解c++默默编写并调用哪些函数 如果自己没声明,编译器会声明一个copy构造函数,一个copy赋值操作符和一个析构函数。此外,如果没有声明任何构造函数,编译器会声明一个default构造函数(如果已经声明了构造函数,编译器不会创建default构造函数)。编译器生成的所有这些函数都是pub 阅读全文

posted @ 2017-07-30 19:25 合唱团abc 阅读 (89) | 评论 (0) 编辑

【effective c++】定制new和delete

摘要:条款49: 了解new-handler的行为 operator new 和 operator delete只适合用来分配单一对象。array所用的内存由operator new[]分配出来,并由operator delete[] 释放。 1、了解new-handler的行为 当operator ne 阅读全文

posted @ 2017-03-23 21:55 合唱团abc 阅读 (64) | 评论 (0) 编辑

【effective c++】模板与泛型编程

摘要:模板元编程:在c++编译器内执行并于编译完成时停止执行 1.了解隐式接口和编译期多态 面向对象编程总是以显式接口(由函数名称、参数类型和返回类型构成)和运行期多态(虚函数)解决问题 模板及泛型编程:对template参数而言,接口是隐式的,基于有效表达式的约束,而多态则是通过模板实例化和函数重载解析 阅读全文

posted @ 2016-09-20 20:49 合唱团abc 阅读 (270) | 评论 (0) 编辑

【effective c++】设计与声明

摘要:1.让接口容易被正确使用,不易被误用 避免无端与内置类型不兼容,提供行为一致的接口 2.设计class犹如设计type 3.以pass-by-reference-to-const替换pass-by-value pass-by-reference-to-const比较高效(避免了copy构造),当一个 阅读全文

posted @ 2016-09-19 19:17 合唱团abc 阅读 (63) | 评论 (0) 编辑

【effective c++】实现

摘要:1.尽可能延后变量定义式的出现时间 应该延后变量的定义,直到能够给它初值为止.这样不仅能够避免构造(和析构)非必要对象,还可以避免无意义的default构造行为 方法A:一个构造函数 + 1个析构函数 + n个赋值操作 方法B:n个构造函数 + n个析构函数 通常采用方法B,方法A中w的作用域比做法 阅读全文

posted @ 2016-09-11 15:25 合唱团abc 阅读 (101) | 评论 (0) 编辑

【effective c++】继承与面向对象设计

摘要:1.确定你的public继承塑造出is-a关系 public继承意味着is-a.适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived classes对象也都是一个base class对象,反过来不成立。 2.避免隐藏继承而来的名称 c 阅读全文

posted @ 2016-08-29 18:31 合唱团abc 阅读 (74) | 评论 (0) 编辑

【effective c++】资源管理

摘要:以对象管理资源的观念常被称为“资源取得时机便是初始化时机”(RAII) auto_ptr被销毁时会自动删除它所指之物,所以一定要注意别让多个auto_ptr同时指向同一对象,否则对象会被删除多次,行为未定义 auto_ptr有一个性质:若通过拷贝构造函数或拷贝赋值运算符复制它们,它们会变成NULL, 阅读全文

posted @ 2016-07-29 19:46 合唱团abc 阅读 (86) | 评论 (0) 编辑

条款50: 提高对C++的认识

摘要:class Base {public: virtual void f(int x);};class Derived: public Base {public: virtual void f(double *pd);};Derived *pd = new Derived;pd->f(10); ... 阅读全文

posted @ 2014-08-25 13:46 合唱团abc 阅读 (55) | 评论 (0) 编辑

条款47: 确保非局部静态对象在使用前被初始化

摘要:Directory tempDir; // 临时文件目录 现在,初始化顺序的问题变得很明显了:除非theFileSystem在tempDir之前被初始化,否则,tempDir的构造函数将会去使用还没被初始化的theFileSystem。但theFileSystem和tempDir是由不同的人在不同的 阅读全文

posted @ 2014-08-25 13:32 合唱团abc 阅读 (116) | 评论 (0) 编辑

条款45: 弄清C++在幕后为你所写、所调用的函数

摘要:如果你没有声明下列函数,体贴的编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。换句话说,如果你这么写:class Empty{};和你这么写是一样的:cla... 阅读全文

posted @ 2014-08-24 13:48 合唱团abc 阅读 (130) | 评论 (0) 编辑

条款42: 明智地使用私有继承

摘要:第一个规则是,和公有继承相反,如果两个类之间的继承关系为私有,编译器一般不会将派生类对象(如Student)转换成基类对象(如Person)第二个规则是,从私有基类继承而来的成员都成为了派生类的私有成员,即使它们在基类中是保护或公有成员,即派生类对象不能访问基类的所有成员class person{}... 阅读全文

posted @ 2014-08-24 13:26 合唱团abc 阅读 (49) | 评论 (0) 编辑

条款41: 区分继承和模板

摘要:· 当对象的类型不影响类中函数的行为时,就要使用模板来生成这样一组类。· 当对象的类型影响类中函数的行为时,就要使用继承来得到这样一组类。下面的代码通过定义一个链表来实现Stack类,假设堆栈的对象类型为T:templateclass stack{public: stack(); ~st... 阅读全文

posted @ 2014-08-24 13:12 合唱团abc 阅读 (80) | 评论 (0) 编辑

条款39: 避免 "向下转换" 继承层次

摘要:基类指针不能调用派生类的独有的成员,即使基类指针指向派生类对象,因为编译器是根据指针的静态类型来确定调用对象在内存中占据的空间的。此时可以使用static_cast来转换,但不要这么做,因为向下转换难看、容易导致错误,而且使得代码难于理解、升级和维护,static_cast不会进行类型检查,即使指针... 阅读全文

posted @ 2014-08-21 13:29 合唱团abc 阅读 (157) | 评论 (0) 编辑

条款38: 决不要重新定义继承而来的缺省参数值

摘要:虚函数是动态绑定而缺省参数值是静态绑定的,当基类和派生类对同一个虚函数设置缺省参数值时,只有基类的缺省参数值起作用。对象的静态类型是指你声明的存在于程序代码文本中的类型,对象的动态类型是由它当前所指的对象的类型决定的。即,对象的动态类型表示它将执行何种行为。虚函数是动态绑定的,意思是说,虚函数通过哪... 阅读全文

posted @ 2014-08-20 14:11 合唱团abc 阅读 (59) | 评论 (0) 编辑

条款36: 区分接口继承和实现继承

摘要:作为类的设计者,有时希望派生类只继承成员函数的接口(声明);有时希望派生类同时继承函数的接口和实现,但允许派生类改写实现;有时则希望同时继承接口和实现,并且不允许派生类改写任何东西。class Shape {public: virtual void draw() const = 0; virtu... 阅读全文

posted @ 2014-08-20 13:57 合唱团abc 阅读 (137) | 评论 (0) 编辑

条款34: 将文件间的编译依赖性降至最低

摘要:class Person {public: Person(const string& name, const Date& birthday, const Address& addr, const Country& country); virtual ~Person(); ...... 阅读全文

posted @ 2014-08-18 14:37 合唱团abc 阅读 (64) | 评论 (0) 编辑

条款33: 明智地使用内联

摘要:调用函数实际上将程序执行顺序转移到函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。当程序运行到某个节点时,如果发现有函数调用语句(函数要事先声明或者事先定义),程序... 阅读全文

posted @ 2014-08-18 14:09 合唱团abc 阅读 (88) | 评论 (0) 编辑

条款32: 尽可能地推迟变量的定义

摘要:// 此函数太早定义了变量"encrypted"string encryptPassword(const string& password){ string encrypted;//默认构造函数初始化 if (password.length() < MINIMUM_PASSWORD_LENGTH... 阅读全文

posted @ 2014-08-18 13:38 合唱团abc 阅读 (83) | 评论 (0) 编辑

条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用

摘要:先看第一种情况:返回一个局部对象的引用。它的问题在于,局部对象 ----- 顾名思义 ---- 仅仅是局部的。也就是说,局部对象是在被定义时创建,在离开生命空间时被销毁的。所谓生命空间,是指它们所在的函数体。当函数返回时,程序的控制离开了这个空间,所以函数内部所有的局部对象被自动销毁。因此,如果返回... 阅读全文

posted @ 2014-08-18 12:53 合唱团abc 阅读 (894) | 评论 (0) 编辑

条款29: 避免返回内部数据的句柄

摘要:假设b是一个const string对象:class string {public: string(const char *value); // 具体实现参见条款11 ~string(); // 构造函数的注解参见条款m5 opera... 阅读全文

posted @ 2014-08-17 13:19 合唱团abc 阅读 (57) | 评论 (0) 编辑

条款27: 如果不想使用隐式生成的函数就要显式地禁止它

摘要:假设想写一个类模板Array,它所生成的类除了可以进行上下限检查外,其它行为和C++标准数组一样。设计中面临的一个问题是怎么禁止掉Array对象之间的赋值操作,因为对标准C++数组来说赋值是不合法的:double values1[10];double values2[10];values1 = va... 阅读全文

posted @ 2014-08-16 14:29 合唱团abc 阅读 (47) | 评论 (0) 编辑

条款26: 当心潜在的二义性

摘要:class B; // 对类B提前声明 // class A {public: A(const B&); // 可以从B构造而来的类A};class B {public: operator A() const; // 可以从A转换而来的类B};void f(c... 阅读全文

posted @ 2014-08-16 14:26 合唱团abc 阅读 (52) | 评论 (0) 编辑

条款23: 必须返回一个对象时不要试图返回一个引用

摘要:class rational {public: rational(int numerator = 0, int denominator = 1); ...private: int n, d; // 分子和分母friend const rational ... 阅读全文

posted @ 2014-08-16 14:00 合唱团abc 阅读 (105) | 评论 (0) 编辑

条款22: 尽量用“传引用”而不用“传值”

摘要:c语言中,什么都是通过传值来实现的,c++继承了这一传统并将它作为默认方式。除非明确指定,函数的形参总是通过“实参的拷贝”(拷贝构造函数)来初始化的,函数的调用者得到的也是函数返回值的拷贝。为避免这种潜在的昂贵的开销,就不要通过值来传递对象,而要通过引用。通过引用来传递参数还有另外一个优点:它避免了... 阅读全文

posted @ 2014-08-16 13:38 合唱团abc 阅读 (101) | 评论 (0) 编辑

条款21: 尽可能使用const

摘要:对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const,还有,两者都不指定为const: 声明迭代器为const表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改变的,如果希望迭代器所指的东西不可被改动,可以使用const_iterato 阅读全文

posted @ 2014-08-15 13:17 合唱团abc 阅读 (77) | 评论 (0) 编辑

条款十九: 分清成员函数,非成员函数和友元函数

摘要:成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38),就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。如果函数不必是虚拟的,情况就稍微复杂一点。看下面表示有理数的一个类:class rational {public: rati... 阅读全文

posted @ 2014-08-14 13:24 合唱团abc 阅读 (88) | 评论 (0) 编辑

条款十七: 在operator=中检查给自己赋值的情况

摘要:在赋值运算符中要特别注意可能出现别名的情况,其理由基于两点。其中之一是效率。如果可以在赋值运算符函数体的首部检测到是给自己赋值,就可以立即返回,从而可以节省大量的工作,否则必须去实现整个赋值操作。另一个更重要的原因是保证正确性。一个赋值运算符必须首先释放掉一个对象的资源(去掉旧值),然后根据新值分配... 阅读全文

posted @ 2014-08-11 14:13 合唱团abc 阅读 (373) | 评论 (0) 编辑

条款十六: 在operator=中对所有数据成员赋值

摘要:当涉及到继承时,派生类的赋值运算符也必须处理它的基类成员的赋值!否则,当派生类对象向另一个派生类对象赋值时,只有派生类部分赋值了。看看下面:class base {public: base(int initialvalue = 0): x(initialvalue) {}private: int... 阅读全文

posted @ 2014-08-11 14:05 合唱团abc 阅读 (85) | 评论 (0) 编辑

条款十五: 让operator=返回*this的引用

摘要:c++程序员经常犯的一个错误是让operator=返回void,这好象没什么不合理的,但它妨碍了连续(链式)赋值操作,所以不要这样做。一般情况下几乎总要遵循operator=输入和返回的都是类对象的引用的原则,然而有时候需要重载operator=使它能够接受不同类型的参数。例如,标准string类型... 阅读全文

posted @ 2014-08-11 13:40 合唱团abc 阅读 (302) | 评论 (0) 编辑

条款十三: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同

摘要:templateclass array {public: array(int lowbound, int highbound); ...private: vector data; // 数组数据存储在vector对象中 ... 阅读全文

posted @ 2014-08-11 13:09 合唱团abc 阅读 (178) | 评论 (0) 编辑

条款十二: 尽量使用初始化而不要在构造函数里赋值

摘要:看这样一个模板,它生成的类使得一个名字和一个t类型的对象的指针关联起来。 在写namedptr构造函数时,必须将参数值传给相应的数据成员。有两种方法来实现。第一种方法是使用成员初始化列表: 第二种方法是在构造函数体内赋值: 从纯实际应用的角度来看,有些情况下必须用初始化。特别是const和引用数据成 阅读全文

posted @ 2014-08-09 15:51 合唱团abc 阅读 (236) | 评论 (0) 编辑

条款十一: 为需要动态分配内存的类声明一个拷贝构造函数和一个拷贝赋值运算符

摘要:看下面一个表示string对象的类:// 一个很简单的string类class string {public: string(const char *value); ~string(); ... // 没有拷贝构造函数和operator=pr... 阅读全文

posted @ 2014-08-09 15:34 合唱团abc 阅读 (274) | 评论 (0) 编辑

条款十: 如果写了operator new就要同时写operator delete

摘要:为什么有必要写自己的operator new和operator delete?答案通常是:为了效率。缺省的operator new和operator delete具有非常好的通用性,它的这种灵活性也使得在某些特定的场合下,可以进一步改善它的性能。尤其在那些需要动态分配大量的但很小的对象的应用程序里,... 阅读全文

posted @ 2014-08-07 14:49 合唱团abc 阅读 (180) | 评论 (0) 编辑

条款九: 避免隐藏标准形式的new

摘要:因为内部范围声明的名称会隐藏掉外部范围的相同的名称,所以对于分别在类的内部和全局声明的两个相同名字的函数f来说,类的成员函数会隐藏掉全局函数class x {public: void f(); // operator new的参数指定一个 // new-hander(new的出错处理)函数 ... 阅读全文

posted @ 2014-08-06 15:01 合唱团abc 阅读 (62) | 评论 (0) 编辑

条款八: 写operator new和operator delete时要遵循常规

摘要:自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致。实际做起来也就是:要有正确的返回值;可用内存不够时要调用出错处理函数(见条款7);处理好0字节内存请求的情况。此外,还要避免不小心隐藏了标准形式的new,不... 阅读全文

posted @ 2014-08-06 14:49 合唱团abc 阅读 (74) | 评论 (0) 编辑

条款五:对应的new和delete要采用相同的形式

摘要:string *stringarray = new string[100];...delete stringarray;上述程序的运行情况将是不可预测的。至少,stringarray指向的100个string对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用。用new的时候会发生两件事... 阅读全文

posted @ 2014-08-05 14:17 合唱团abc 阅读 (54) | 评论 (0) 编辑

条款三:尽量用new和delete而不用malloc和free

摘要:malloc和free(及其变体)会产生问题的原因在于它们太简单:他们不知道构造函数和析构函数。假设用两种方法给一个包含10个string对象的数组分配空间,一个用malloc,另一个用new:string *stringarray1 =static_cast(malloc(10 * sizeof(... 阅读全文

posted @ 2014-08-04 14:24 合唱团abc 阅读 (57) | 评论 (0) 编辑

条款一:尽量使用const、inline而不是#define

摘要:编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。 解决这个问题的方案很简单:不 阅读全文

posted @ 2014-08-04 14:05 合唱团abc 阅读 (85) | 评论 (0) 编辑

原文地址:https://www.cnblogs.com/cx2016/p/12926142.html