构造/析构/赋值运算

摘自effective C++第2部分构造/析构/赋值运算
5. 了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)
编译器可以暗自为class创建default构造函数,copy构造函数,copy assignment操作符,以及析构函数
C++中,如果自己没有声明,编译器就会为它声明(编译器版本的)一个copy构造函数,一个copy assignment操作符和一个析构函数.此外,如果你没有声明任何构造函数,编译器也会为你声明一个default构造函数.所有这些函数都是public且inline.

class Empty {
public:
	Empty() {...}											//default构造函数
	Empty(const Empty& rhs) {...}							//copy构造函数
	~Empty() {...}											//析构函数,是否该是virtual,见稍后说明
	Empty& operator=(const Empty& rhs) {...}				//copy assignment操作符
};

C++中,声明一个构造函数,编译器不再为他创建default构造函数.这很重要,意味如果你用心设计一个class,其构造函数要求实参,你就无须担心编译器会毫无挂虑地为你添加一个无实参构造函数(即default构造函数)而遮盖掉你的版本
6. 若不想使用编译器自动生成的函数,就该明确拒绝(Explicitly disallow the use of complier-generated functios you do not want)
为驳回编译器自动提供的机能,可将相应的成员函数声明为private并且不予实现.使用像Uncopyable这样的base class也是一种做法

class noncopyable
{
 public:
  noncopyable(const noncopyable&) = delete;
  void operator=(const noncopyable&) = delete;

 protected:
  noncopyable() = default;
  ~noncopyable() = default;
};
  1. 为多态基类声明virtual析构函数(Declare destructors virtual in polymorphic base classes)
    polymorphic(带多态性质的) base classea应该声明一个virtual析构函数.如果class带有任何virtual函数,他就应该拥有一个virtual析构函数
    Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数
  2. 别让异常逃离析构函数(Prevent exceptions from leaving destructors)
    析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下他们(不传播)或结束程序
    如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作
class DBConn {
public:
	...
	void close()						    	//供客户使用的新函数
	{
		db.close();
		closed = true;
	}
	~DBConn()
	{
		if (!closed) {
			try {							    //关闭连接(如果客户不那么做的话)
				db.close();
			}
			catch (...) {					    //如果关闭动作失败
				制作运转记录,记录对close的调用失败;  //记录下来并结束程序
				...								//或吞下异常
			}
		}
	}
private:
	DBConnection db;
	bool closed;
}
  1. 绝不在构造和析构过程中调用virtual函数(Nerver call virtual functions during construction or destruction)
    在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)
  2. 令operator= 返回一个reference to this(Having assignment operators return a reference to this)
    *令赋值(assignment)操作符返回一个reference to this
    这只是个协议,并无强制性.如果不遵循它,代码一样可通过编译.然而这份协议被所有内置类型和标准程序库提供的类型string, vector, complex, trl::shared_ptr或即将提供的类型共同遵守.因此除非你有一个标新立异的好理由,不然还是随众吧
  3. 在opertor= 中处理"自我赋值"(Handle assignment to self in operatop=)
    确保当对象自我赋值是operator=有良好行为.其中技术包括比较"来源对象"和"目标对象"的地址,精心周到的语句顺序,以及copy-and-swap
    确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象是,其行为仍然正确.
Widget& Widget::operator=(const Widget& rhs)
{
	if (this == &rhs) return *this;

	delete pb;
	pb = new Bitmap(*rhs.pb);
	return *this;
}
Widget& Widget::operator=(const Widget& rhs)
{
	Bitmap *pOrig = pb;
	pb = new Bitmap(*rhs.pb);
	delete pOrig;
	return *this;
}
class Widget {
...
void swap(Widget& rhs);
...
};

//reference
Widget& Widget::operator=(const Widget& rhs)    
{
	Widget temp(rhs);
	swap(temp);
	return *this;
}
//pass by value
Widget& Widget::operator=(Widget rhs)
{
	swap(rhs);
	return *this;
}
  1. 复制对象时勿忘其每一个成分(Copy all parts of an object)
    Copying函数应该确保复制"对象内的所有成员变量"及"所有base class成分"
    不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个coping函数共同调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值