
Effective C++
文章平均质量分 84
Sunshine_top
安安静静、认认真真完成自己的事情
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
条款08 别让异常逃离析构函数
结论:1. 析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该能够捕捉任何异常,然后吞下他们(不传播)或结束程序。2. 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而不是在析构函数中)执行该操作。 C++ 不禁止但不鼓励从析构函数引发异常。考虑:class Widget {pub原创 2015-02-03 20:04:34 · 2287 阅读 · 0 评论 -
条款23 宁以non-member、non-friend替换member函数
总结: 用非成员非友元函数取代成员函数。这样做可以提高封装性,包装弹性,和机能扩充性 想象一个用来表示网页浏览器浏览器的类。这样一个类可能提供的大量函数中,有一些用来清空下载元素高速缓存区、清空访问过的URLs历史,以及从系统移除所有cookies的功能:class WebBrowser {public: ... void clearCache();原创 2015-04-11 20:13:30 · 1543 阅读 · 0 评论 -
条款21 必须返回对象时,别妄想返回其reference
总结: 绝不要返回一个local栈对象的指针或引用;绝不要返回一个被分配的堆对象的引用;绝不要返回一个局部对象有可能同时需要多个这样的对象的指针或引用。 条款4中给出了“在单线程环境中合理返回局部静态对象的引用” 一旦程序员抓住对象传值的效率隐忧,很多人就会一心一意根除传值的罪恶。他们不屈不挠地追求传引用的纯度,但他们全都犯了一个致命的错误:原创 2015-04-11 16:03:27 · 1502 阅读 · 0 评论 -
条款25 考虑写出一个不抛异常的swap函数
总结: 如果 std::swap 对于你的类型来说是低效的,请提供一个 swap 成员函数,并确保你的 swap 不会抛出异常。 如果你提供一个成员 swap,请同时提供一个调用成员swap的非成员swap。对于类(非模板),还要特化 std::swap。 调用swap时,请为std::swap使用一个using声明式,然后在调用 swap时不使用任何names原创 2015-04-12 09:13:11 · 1979 阅读 · 0 评论 -
条款26 尽可能延后变量定义式的出现时间
总结: 尽可能延后变量定义式的出现,这样做可增加程序的清晰度并改善程序效率。定义一个类变量,当程序的控制流到达这个变量定义时,你就必须承担起构造和析构的负担,所以我们要尽量减少定义一些我们不用的对象。string encryptPassword(const std::string& password) { using namespace std; stri原创 2015-04-23 09:43:41 · 1503 阅读 · 0 评论 -
条款04 确定对象被使用前已先被初始化
总结:1. 为内置型对象进行手工初始化,因为C++不保证初始化它们。2. 构造函数最好使用成员初值列(memberinitialization list),而不要在构造函数本体内使用赋值操作(assignment)。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。3. 为免除"跨编译单元之初始化次序"问题,请以local static对象替换non-local原创 2015-04-13 09:06:21 · 1373 阅读 · 0 评论 -
条款03 尽可能使用const
总结: 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。 编译器强制实施bitwise constness,但你编写程序时应该使用"概念上的常量性"(conceptual constness)。 当const和non-const成员函数有着实质等价的实现时,令n原创 2015-04-12 21:20:22 · 1441 阅读 · 0 评论 -
条款27 尽量少做转型动作
隐式转换在谈及显式转换之前,先简单说说隐式转换。int ival = 0;ival = 3.541 + 3; //doubl向int转换会丢失精度,编译器会警告:“=”从double到int转换可能会丢失数据,结果ival等于6 整数3被转换为double类型,然后执行浮点类型加法操作,得double类型结果6.541,然后将double类型值赋值给int类原创 2015-06-30 09:25:01 · 1232 阅读 · 0 评论 -
条款09 绝不在构造和析构过程中调用virtual函数
总结:在构造或析构期间不要调用 virtual函数,因为这样的调用从不下降至派生类(比起当前执行构造函数和析构函数的那层)。 不应该在构造或析构期间调用 virtual函数,因为这样的调用不会如你想象那样工作,而且会让你很郁闷。作为 Java 或 C# 程序员,也要更加注意本条款,因为这是C++与它们不相同的一个地方。 假设你有一套模拟股票交易的类继原创 2015-02-04 20:57:33 · 2200 阅读 · 0 评论 -
条款37 绝不要重新定义继承而来的缺省参数值
总结:不要重新定义一个继承而来的缺省参数值,因为缺省参数值是静态绑定,而virtual函数(你唯一应该覆写的东西)是动态绑定。我们应该知道,virtual函数是动态绑定(dynamically bound),缺省参数值却是静态绑定(statically bound)。对象的静态类型(static type)是它在程序中被声明时采用的类型,例如class Shape{原创 2015-07-26 11:21:33 · 1010 阅读 · 0 评论 -
条款32 确定你的public继承塑模出is-a关系
结论:"public继承"意味is-a。适用于base class身上的每一件事情一定也适用与derived class身上,因为每一个derived class对象也都是一个base class对象。 public继承意味着“is-a”关系。它的意思是:如果B以public形式继承自A,那么B类型对象肯定是一个A对象,反之不成立。A是B的一种抽象,B是A的特例。任何原创 2015-07-04 16:17:04 · 1119 阅读 · 0 评论 -
条款38 通过复合塑膜出has-a或"根据某物实现"
结论:复合的意义和public继承完全不同.(public继承参考:条款32 确定你的public继承塑模出is-a关系)在应用域,复合意味着has-a(有一个).在实现域,复合意味着is-implemented-in-terms-of(根据某物实现出)复合(composition)是类型之间的一种关系,当某种类型的对象内含其他类型的对象,便是这种关系:class Ad原创 2015-07-04 16:42:17 · 992 阅读 · 0 评论 -
条款07 为多态基类声明virtual析构函数
为多态基类声明虚析构函数 用于多态用途的继承中,如果没有为基类声明virtual析构函数会引发问题,看下面的代码。class A {public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } //virtual ~A() { cout << "~A()" << endl; } vi原创 2015-01-20 09:43:25 · 3107 阅读 · 0 评论 -
条款03-06
Effective C++笔记原创 2014-11-03 20:27:48 · 1483 阅读 · 0 评论 -
条款22 将成员变量声明为private
总结: 切记声明数据成员为private。它为客户提供了访问数据的一致,细微划分的访问控制,允许约束条件获得保证,而且为类的作者提供了实现上的弹性。 protec并不比public更具有封装性。不应该将数据成员声明为public的三个理由:一、语法一致性 如果数据成员不是public的,客户访问一个对象的唯一方法就是通过成员函数。如果在pu原创 2015-04-11 17:37:34 · 1778 阅读 · 0 评论 -
条款10 令operator=返回一个reference to *this
总结:重载赋值运算符(包括所有赋值相关的运算)、前自增和前自减运算符(++a、--a)都返回*this的引用。而后自增和后自减(a++、a--)返回的是对象。关于自增、自减运算符的重载见文本末尾部分。 关于赋值的一件有意思的事情是你可以把它写成连锁形式。int x, y, z;x = y = z = 15; // 赋值连锁形式,相当于x = (y = (z = 15原创 2015-02-04 21:11:49 · 1738 阅读 · 0 评论 -
条款11 在operator=中处理“自我赋值”
结论:(1)确保当一个对象自我赋值的时候,operator= 行为良好。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及 copy-and-swap。 · (2)确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。 自我赋值发生在对象被赋值给自己时,它合法,所以不要认定客户绝不会这么做。此原创 2015-02-05 20:50:37 · 1740 阅读 · 0 评论 -
条款15 在资源管理类中提供对原始资源的访问
总结:API 经常需要访问原始资源,所以每一个 RAII 类都应提供取得它所管理资源的方法。访问可以通过显式转换或者隐式转换进行。通常,显式转换更安全,而隐式转换对客户来说更方便。很多 API 直接涉及资源,所以除非你计划坚决放弃使用这样的 API(太不实际),否则,你就要经常绕过资源管理类而直接处理原始资源(raw resources)。例如使用类似 auto_p原创 2015-03-11 21:19:38 · 1314 阅读 · 0 评论 -
条款12 复制对象勿忘其每一个成分
总结:1. 拷贝函数应该保证拷贝一个对象的所有数据成员以及所有的基类部分。2. 不要试图依据一个拷贝函数实现另一个。作为代替,将通用功能放入第三个供双方调用的函数。 设计良好的面向对象系统中,封装了对象内部,仅留两个函数用于对象的拷贝:拷贝构造函数和拷贝赋值运算符,统称为拷贝函数。编译器生成版的copy函数会拷贝被拷贝对象的所以成员变量。考虑一个表现顾客的原创 2015-03-11 21:05:56 · 1308 阅读 · 0 评论 -
条款17以独立语句将newed对象置入智能指针
总结: 以独立语句中将 new 出来的对象存入智能指针。如果疏忽了这一点,当异常发生时,有可能导致难以察觉的资源泄漏。假设我们有一个函数用来揭示处理程序的优先权,另一个函数用来在某动态分配所得的Widget上进行某些带有优先权的处理:int priority();void processWidget(std::tr1::shared_ptr pw, int prio原创 2015-03-11 21:28:11 · 1290 阅读 · 0 评论 -
条款16 成对使用new和delete时要采取相同形式
总结: 如果你在 new表达式中使用了[],你必须在对应的 delete表达式中使用[]。如果你在new表达式中没有使用[],你也不必在对应的 delete表达式中不使用[]。 delete的最大问题在于:即将删除的内存之内究竟存在多少对象?这个问题的答案决定了有多少个析构函数必须被调用。当你对一个指针使用 delete,唯一能够让delete知道内存中是否存原创 2015-03-11 21:20:14 · 1269 阅读 · 0 评论 -
条款13 以对象管理资源
总结:1. 为了防止资源泄漏,使用 RAII 对象,在 RAII 对象的构造函数中获得资源并在析构函数中释放它们。2. 两个通用的 RAII 是 tr1::shared_ptr 和 auto_ptr。前者通常是更好的选择,因为其拷贝行为比较直观。若选择 auto_ptr,复制动作会使被复制物指向null。假设我们使用一个用来塑模投资行为(例如股票、债券等)的程序库,各种各样的原创 2015-03-11 21:16:02 · 1408 阅读 · 0 评论 -
条款14 在资源管理类中小心copying行为
总结:拷贝RAII 对象必须一并拷贝它所管理的资源,所以资源的拷贝行为决定了 RAII 对象的拷贝行为。普通的 RAII 类的拷贝行为是:阻止拷贝、引用计数,但其它行为也是有可能的。条款13介绍了作为资源管理类支柱的 Resource Acquisition IsInitialization (RAII) 原则,并描述了 auto_ptr 和 tr1::shar原创 2015-03-11 21:17:51 · 1298 阅读 · 0 评论 -
条款20 宁以pass-by-reference-to-const替换pass-by-value
总结:1、尽量以pass-by-reference-to-const替换pass-by-value。前者更高效且可以避免切断问题。2、这条规则并不适用于内建类型及STL中的迭代器和函数对象类型。对于它们,pass-by-value通常更合适。 缺省情况下,C++以传值方式将对象传入或传出函数(这是一个从C继承来的特性)。除非你另外指定,否则函数的参数就会以实际参数的副原创 2015-03-12 20:27:15 · 1279 阅读 · 0 评论 -
条款19 设计class 犹如设计type
在 C++ 中,就像其它面向对象编程语言,可以通过定义一个新的类来定义一个新的类型。作为一个C++开发者,你的大量时间就这样花费在扩张你的类型系统。这意味着你不仅仅是一个类的设计者,而且是一个类型的设计者。重载函数和运算符,控制内存分配和回收,定义对象的初始化和终结过程——这些全在你的掌控之中。因此你应该在类设计中倾注大量心血,就如语言设计者在语言内置类型设计中所倾注的大量心血。设计良好的类是原创 2015-03-12 20:05:40 · 1482 阅读 · 0 评论 -
条款18 让接口容易被正确使用,不易被误用
总结:1、好的接口很容易被正确使用,不容易被误用。你应该在你的所有接口中努力达成这些性质。2、促进正确使用的方法包括接口的一致性,以及与内置类型的行为兼容。3、预防错误的方法包括创建新的类型,限定类型的操作,约束对象的值,以及消除客户的资源管理职责。4、tr1::shared_ptr 支持自定义 deleter。这可以防止 cross-DLL 问题,能用于自动解锁互斥体(mutex原创 2015-03-12 19:14:12 · 1127 阅读 · 0 评论 -
条款24 若所有参数皆需类型转换,请为此采用non-member函数
总结: 如果你需要在一个函数的所有参数(包括被 this 指针所指向的那个)上使用类型转换,这个函数必须是一个非成员。让一个类支持隐式类型转换通常是一个不好的主意。当然,这条规则有一些例外:在创建数值类型时。例如,如果你设计一个用来表现有理数的类,允许从整数到有理数的隐式转换:class Rational {public: Rational(int numera原创 2015-04-11 20:50:30 · 1318 阅读 · 0 评论 -
条款34 区分接口继承和实现继承
总结:1. 接口继承&实现继承不同。在public继承之下,derived classes总是继承base class的接口。2. pure virtual纯虚函数只具体指定接口继承。3. Impure virtual普通虚函数具体指定接口继承及缺省实现继承。4. non-virtual普通函数具体指定接口继承以及强制性实现继承。 公有继原创 2015-07-06 09:03:29 · 990 阅读 · 0 评论