- 博客(24)
- 收藏
- 关注
原创 条款29:为“异常安全”而努力
异常安全函数:即使发生异常也不会泄露资源或允许任何数据结构败坏。异常安全函数需要提供以下三个保证之一:基本承诺:如果异常被抛出,程序内的任何事物任然保持在有效状态下。没有任何对象或数据结构会因此而败坏,所有对象都处于一种内部前后一致的状态(如所有的class约束条件都继续获得满足)。然而程序的现实状态恐怕不可预料。强烈保证:如果异常被抛出,程序状态不改变。即函数成功,就是完全成...
2019-03-18 16:59:10 160
原创 C++类型转换符
4个C++类型转换运算符static_castdynamic_castreinterpret_castconst_cast使用static_cast用于在相关类型的指针之间进行转换;显式地执行标准数据类型的类型转换——这种转换原本将自动或隐式地进行;(引起程序员或代码阅读者的注意)用于指针,提供基本的编译阶段检查,确保指针被转换为相关类型。C风格类型转换可将指向一个对象的...
2019-03-18 15:21:02 233
原创 条款22:将成员变量声明为private
为什么要将成员变量声明为private:1.为了语法的一致性;访问class成员变量时不需要使用小括号,访问class成员函数时需要使用小括号。2.使用函数可以让你对成员变量的处理有更精准的控制;可以实现“只读”、“只写”…3.最重要的,是为了封装。封装的好处:可以为所有可能的实现提供弹性;如添加通知、验证class约束条件、在多线程环境中执行同步控制…确保class的约束条件总...
2019-03-13 15:42:27 139
原创 条款21:必须返回对象时,别勉强返回其reference
pass by reference的滥用情况reference的方式返回必然需要创建一个对象,耗费资源,这已经是一个糟糕的行为。1. 返回reference指向一个local对象(也就是在stack空间创建的对象)const Ra& operator*(const Ra& lhs, const Ra& rhs){ Ra ret(lhs.n*rhs.n, lhs.d...
2019-03-13 14:02:08 144
原创 EffectiveC++导读
声明式:告诉某个东西的名称和类型,但略去细节;extern int x; //对象声明式std::size_t numDigits(int number);//函数声明式class Widget; //类声明式template<typename T>...
2019-03-13 10:45:36 228
原创 条款20:尽量以pass-by-reference-to-const替换pass-by-value
尽量以pass-by-reference-to-const替换pass-by-value。前者往往比较高效,并可避免切割问题。以上规则并不适用于内置类型,以及STL迭代器的和函数对象。对它们而言,pass-by-value往往比较适当。PS:当面对STL迭代器和函数对象时,我们有责任看看它们是否高效且不受切割问题影响。pass-by-value对比pass-by-reference:c...
2019-03-12 19:29:47 181
原创 条款18:让接口容易被正确使用,不易被误用
好的接口应该具备的条件:容易被正确使用;不容易被误用;接口容易被正确使用的方法保持接口的一致性;与内置类型的行为兼容阻止接口被误用的方法1. 导入新类型struct Day{explicit Day(int d):val(d){}int val;};struct Month{explicit Month(int m):val(m){}int val;};st...
2019-03-12 16:07:08 170
原创 条款17:以独立语句将newed对象置入智能指针
processWidget(shared_ptr<Widget>(), priority());上述调用虽然使用了“对象管理式资源”,依然可能泄露资源。调用processWidget前,编译器做了三件事:调用priority()执行new Widget调用shared_ptr构造函数对priority()的调用次序不确定,如若按以下次序执行:调用priority(...
2019-03-12 11:57:45 127
原创 条款16:成对使用new和delete时要采取相同形式
new[] 对应 delete[]new 对应 deletestd::string* strPtr1 = new std::string;std::string* strPtr2 = new std::string[100];...delete strPtr1;delete [] strPtr2;尽量不要对数组形式做typedefs动作。可改用STL容器。typedef std:...
2019-03-12 11:37:34 108
原创 条款15:在资源管理类中提供对原始资源的访问
APIs往往要求访问原始资源(raw resource),所以每一个RAII class应该提供一个“取得管理资源”的办法对原始资源的访问可以有显式转换和隐式转换。显式转换比较安全;隐式转换比较方便;显式转换:智能指针的get()函数隐式转换:智能指针的operator->和operator*FontHandle getFont(); //C APIvoid release...
2019-03-12 11:29:37 285
原创 条款14:在资源管理类中小心copying行为
RAII对象被复制时的几种选择:(前两种最常用)禁止复制class A:private Uncopyable{...};引用计数,复制时将资源的“被引用数”递增。RAIIclass包含一个shared_ptr成员变量即可。shared_ptr可以定制删除器,即当引用为0时触发。class Lock{public: explict Lock(Mutex* pm):mutexPt...
2019-03-11 23:54:12 150
原创 条款13:以对象管理资源
以对象管理资源的两个关键:获得资源后立即放进管理对象内。该观念常被称为RAII(资源获取时便初始化)管理对象运用析构函数确保资源被释放。auto_ptr弊端:一旦发生复制,被复制的auto_ptr就会被设为null(受auto_ptrs管理的资源绝对没有一个以上的auto_ptr同时指向它),STL容器容不得auto_ptr。好的替代方案:shared_ptr(引用计数型智能指针),...
2019-03-11 23:13:33 148
原创 条款12:复制对象时勿忘其每一个成分
如果你声明自己的copying函数(拒绝编译器的缺省实现),当你为class添加一个成员变量,你必须同时修改copying函数(也需要修改class的所有构造函数及任何非标准形式的operator=(条款10有个例子)),如果你忘记,编译器不会告诉你。copying函数应该确保复制“对象内的所有成员变量”及“所有基类成分”;class B:public A{private: int b;...
2019-03-11 22:47:35 103
原创 条款11:在operator=中处理“自我赋值”
自行管理资源时,可能在停止使用资源之前意外释放了它。class Data{...};class Widget{ ...private: Data* pd;};Widget&amp; Widget::operator=(const Widget&amp; rw){ delete pd; pd = new Data(*rw.pd); return *this;}operat...
2019-03-11 22:09:29 99
转载 __stdcall、__cdcel和__fastcall三者的区别
__stdcall、__cdecl和__fastcall是三种函数调用协议,函数调用协议会影响函数参数的入栈方式、栈内数据的清除方式、编译器函数名的修饰规则等。调用协议常用场合__stdcall:Windows API默认的函数调用协议。__cdecl:C/C++默认的函数调用协议。__fastcall:适用于对性能要求较高的场合。函数参数入栈方式__stdcall:函数参数由右向左入...
2019-03-11 13:41:31 124
原创 条款10:令operator=返回一个reference to* this
令赋值操作符返回一个reference to* this。不遵循该协议,代码也可通过编译,但是除非有更好的理由,还是应该遵守,因为所有内置类型和STL都遵守该协议。class Widget{public: .. //标准赋值形式,实现“连锁赋值” Widget& operator=(const Widget& rhs) { ... return* this;...
2019-03-10 23:53:32 132
原创 条款09:绝不在构造和析构过程中调用virtual函数
例子:class A{public: A(); virtual void log() const = 0; ...};A:A(){ ... log();}class B:public A{public: virtual void log() const; ...};B b;分析:派生类对象内的基类成分会在派生类自身成分被构造之前先构造妥当。此时,基类构造函...
2019-03-10 23:37:44 76
原创 条款08:别让异常逃离析构函数
析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕获任何异常,然后吞下它们(不传播)或结束程序。如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。...
2019-03-10 22:28:31 75
原创 条款07:为多态基类声明virtual析构函数
例子:class TimeKeeper{public: TimeKeeper::TimeKeeper(); ~TimeKeeper(); ...};class ClockA:public TimeKeeper{...};class ClockB:public TimeKeeper{...};class ClockC:public TimeKeeper{...};//工厂函数:...
2019-03-10 16:46:06 129
原创 条款06:若不想使用编译器自动生成的函数,就该明确拒绝
为驳回编译器自动提供的机能,可将相应的成员函数:声明为private;并且不予实现如仅仅只实现了条件一,member函数和friend函数还是可以调用该类函数。实现方法1:class A{public: ...private: A(const A&amp;); A&amp; operator=(const A&amp;);};实现方法2:使用一个Uncopyable...
2019-03-10 14:14:23 69
原创 条款05:C++默认编写并调用的函数
编译器默认编写的函数编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符,以及析构函数。需要注意的是:唯有当这些函数被需要(被调用),它们才会被编译器创造出来。当声明了任何一个构造函数,编译器将不再为它创建default构造函数。这些函数做了什么default构造函数和析构函数:调用基类和non-static成员变量的构造函...
2019-03-10 11:33:59 108
原创 条款04:确定对象使用前已被初始化
C part of C++ 不保证发生初始化; arraynon-C part of C++ 发生初始化; vector最佳处理办法:永远在使用对象之前先将它初始化。内置类型:手工初始化。非内置类型:确保每一个构造函数都将对象的每一个成员初始化。初始化不等于赋值C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。内置类型不一定有初始化动作。赋值//先调用default...
2019-03-10 00:07:28 75
原创 条款03:尽可能使用const
关键字const出现在星号左边:被指物是常量出现在星号右边:指针自身是常量被指物是常量时,const写在类型前或类型后都行const Widget* buf;Widget const* buf;const与迭代器STL迭代器是以指针为根据塑模出来,所以迭代器的作用就像个T*指针。迭代器不得指向不同的东西,需要为迭代器添加const关键字;迭代器所指的东西不可被改变,需要使用c...
2019-03-08 16:01:39 42
原创 条款02:尽量以const、enum、inline替换#define
尽量以编译器替换预处理器用#define实现常量#define RATIO 1.635缺点:RATIO没进入记号表内,编译器不认识,当出现编译错误时你会因为追踪1.635而浪费时间对于浮点常量,常量定义比宏定义会导致较小量的代码#define 无法创建一个class专属常量好的做法:用常量代替宏const double RATIO = 1.635// 常量字符串const...
2019-03-07 14:25:45 60
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人