effective C++ 阅读笔记 1

std::size_t:位于命名空间std,无符号类型

STL是C++标准程序库的一部分

参数:lhs,rhs

01

C++:组成;

C

面向对象的C++

TEMPLATE C++

STL 容器,迭代器,算法,函数对象的实现

02

const ,enum,inline代替#define

const int pi=3.14;

类中:不能使用define

staticconst int num=5;

intsocres[num];

或者

enum{num=5}; 取地址不合法

intsocres[num];

 

宏使用define可能误用

#define CALL_WITH_MAX(a,b)f((a)>(b)?(a):(b))

int a=5,b=0;

CALL_WITH_MAX(++a,b);a被加1次

CALL_WITH_MAX(++a,b+10);加2次

建议:

纯常量,以const或enums替代#define

类似函数的宏,改用inline函数代替define

03

尽可能使用const

void f1(const widget* pw)

void f1(widget const * pw)等价

const 成员函数不可以更改对象内任何非static成员变量

     除非加上mutable(const函数内可以修改成员变量了)

const ,非const成员函数中避免重复的方法:

非const调用const版本避免代码重复

例如:

const char &operator[](std::size_tposition)const

{

.....

...

...

return text[position];

}

 

 char&operator[](std::size_t position)

{

.....

...

...

return

   const_cast<char &>(static_cast<const text&>(*this));

}

\\

 

04 对象使用前被初始化

对象初始化和赋值的区别:

初始化列表----初始化

:thename(name),theaddress(address)

{}

但--构造函数体内使用赋值

{

the name=name;

theaddress=address;赋值,不是初始化

}

05 C++自动编写哪些函数

empty e1;默认构造函数

empty e2(e1);拷贝构造函数

e2=e1;赋值操作符

析构函数

06

不想使用编译器自动生成的函数,就应该明确拒绝

方法一:继承自:privateuncopyable

方法二:成员函数声明为private,并且不实现

07

多态基类声明virtual析构函数

作用:避免资源泄漏

一个对象经由基类指针,被删除是,基类需要虚析构函数

使用场合:一般类有一个虚函数,才声明虚析构函数

纯虚函数:声明,不实现

          抽象类不能定义对象,仅仅引用&,指针*

          必须为纯虚析构函数提供定义:因为派生后,每一个基类的析构函数都要被调用。

什么时候定义虚析构函数?

带多态性质的基类/带有虚函数:定义虚析构函数

但:若基类不是为了多态用途或不用做基类,不需要虚析

构函数;

例如:string STL容器不用做基类,

08异常不逃出析构函数

C++并没有禁止析构函数吐出异常

不吐出异常的原因?

因为:过早结束程序或未定义行为

建议;析构函数不抛出异常。若析构函数调用的函数可能发生异常,让析构函数捕捉异常,吞下异常或结束程序

09不在构造函数,析构函数中调用虚函数

因为:基类构造期间虚函数不会下降到派生类层次,即在基类构造期间,虚函数不是虚函数

基类的构造函数执行早于派生类的构造函数,

当基类构造函数执行时派生类的成员变量未初始化。

此时调用的虚函数不会下降到派生类层次。(取用未初始化的成分是危险的)

更根本的原因:派生类对象的基类构造期间,对象的类型是基类

此时虚函数,运行期类型信息,例如dynamic_cast,typeid,都把对象当成基类

 

同理,适用于析构函数。一旦派生类析构函数开始执行,对象内的派生类成员变量呈现未定义,

办法:构造函数,析构函数不调用虚函数;

或者派生类构造函数中把参数传递给基类构造函数

 

10 operator=返回一个指向*this的引用

注意两点:

(1)       x=y=z=15;  必须返回引用

(2)       返回*this

例如

widget& operator =(int rhs)

{

...

return *this;

}

11 operator =处理自我赋值

class widget{};

widget w;

w=w;

实现:

方法一:

复制pb所指的东西前别删除pb;

widget&

widget:;operator=(const widget& rhs)

{

bitmap *porig=pb;  不是最高效的 复件,删除原来的,指向新的

pb=new bitmap(*rhs.pb);

delete porig;

return *this;

}

方法二:copy and swap

class widget{

void swap(widget&rhs);

};

 

widget&widget::operator(constwidget&rhs)

{

widget temp(rhs):  

swap(temp):

return *this;

}

或者传递值  多了副本

widget&widget::operator(const widgetrhs)

{

swap(rhs):

return *this;

}

其他不异常安全的实现:

widget&

widget:;operator=(const widget& rhs)

{

delete pb; 不异常安全

pb=new bitmap(*rhs.pb);

return *this;

}

 

自我赋值检测

widget&

widget:;operator=(const widget& rhs)

{

if(this==&rhs) return *this;

delete pb; 不异常安全

pb=new bitmap(*rhs.pb);//可能产生异常

return *this;

}

12 复制对象时要复制每一个成分

实现构造函数时—若初始化列表中实现-----  调用基类的拷贝构造函数  

若构造函数体体实现----------调用基类的赋值函数

 拷贝构造函数+赋值操作符可以消除重复---二者调用公共的函数

 

不要使用拷贝构造函数调用赋值操作符

你可能感兴趣的:(effective C++ 阅读笔记 1)