构造/析构/复制运算

Item5 Know what functions C++ silently writes and calls.

编译器可为一个类默认生成默认构造函数、拷贝构造函数和赋值运算符以及析构函数。注意有指针成员的情况下,默认生成的拷贝构造函数和赋值运算符只是简单的拷贝指针的值,指针指向的数据并不拷贝,即执行的为“浅拷贝”。有可能造成指针指向一个已经释放的内存位置。顾在这样的情况下最好自己实现拷贝构造函数、赋值运算符和析构函数。

Item6 Explicitly disallow the use of compiler-generated functions you do not want.

只要自己定义了Item5照哦给你提到的几个函数,编译器便不再默认生成。如果想阻止对象的拷贝和赋值,可将相应的成员函数声明为private并且不予实现。

如下:

class HomeForSale
{
public:
	HomeForSale()	{	}
private:
	HomeForSale(const HomeForSale&);
	HomeForSale& operator=(const HomeForSale&);
};

或者写一个基类,专门组织拷贝动作

如下:

class Uncopyable
{
protected:
	Uncopyable() {}
	~Uncopyable() {}
private:
	Uncopyable(const Uncopyable&);
	Uncopyable& operator=(const Uncopyable&);
};

class HomeForSale : private Uncopyable
{

};

这样将连接期间的错误转到了编译期间。

Item7 Declare destructors virtual in polumorphic base classes.

如果一个基类为实现多态而设计,则应该为其声明一个virtual析构函数。如果class带有任何virtual函数,也应该拥有一个virtual析构函数。

否则出现的问题如下:如果用一个基类指针指向派生类的对象,则在delete基类指针的时候,会出现派生类成分没有被销毁的后果。

如果一个类的设计不是作为基类使用,不是为了多态性,不应该声明virtual析构函数。

Item8 Prevent exceptions from leaving destructors.

析构函数不要抛出异常。如果被析构函数调用的函数可能抛出异常,则析构函数应该捕捉异常,然后吞下他们。

以下为close抛出异常后,程序异常终止。或者去掉std::abort的调用,析构函数将异常吞下。

class DBConnection
{
public:
	static DBConnection create();
	void close();   //失败则抛出异常
};

class DBConn
{
public:
	~DBConn()
	{
		try
		{
			db.close();
		}
		catch(...)
		{
                        制作运转记录,记下对close的调用失败;
			std::abort();
		}
	}
private:
	DBConnection db;
};


如果客户需要对某个操作函数运行期间抛出的异常做出反应,则类应该提供一个普通的函数执行该该做,而非析构函数。

 

class DBConn
{
public:
	void close()
	{
		db.close();
		closed=true;
	}
	~DBConn()
	{
		try
		{
			if(!closed)
			{
				db.close();
			}
		}
		catch(...)
		{
			std::abort();
		}
	}
private:
	DBConnection db;
	bool closed;
};

由客户在调用DBConn的close的过程中,去捕捉异常并进行一场处理。

Item9 Never class virtual functions during constructions or destructions.

在构造函数和析构函数中,调用virtual函数,类调用从不下降至派生类。因为在构造的过程中,先构造基类的成员,此时基类还未构造,顾不可能调用一个未构造的对象的成员。“早基类构造期间,virtual函数不是virtual函数”。析构也是同样的道理,析构的过程与构造的过程相反,等到调用基类的析构函数的时候,派生类的析构函数已经调用过。

Item10 Have assignment operators return a reference to *this.

class Widget
{
public:
	Widget& operator=(const Widget& rhs)
	{
		....
		return *this;
	}
};


对于+=、-=、*=等也成立。

Item11 Handle assignment to self in operator=.

处理方式有如下几种:(1)进行“自我赋值”的检查:

class Widget
{
public:
	Widget& operator=(const Widget& rhs)
	{
		if(this==&rhs)
			return *this;
		...
	}
};


(2)复制原有对象的内容

class Bitmap
{

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

(3)copy and swap技术

class Widget
{
public:
	void swap(Widget& rhs);
	Widget& operator=(const Widget& rhs);
};

Widget& Widget::operator=(const Widget& rhs)
{
	Widget temp(rhs);
	swap(temp);
	return *this;
}

Item 12 Copy all parts of an object.

如果要自定义拷贝构造函数和赋值运算符,则要注意拷贝对象内的所有成员变量及基类的成份。

例如:

class Customer
{
public:
	Customer(const Customer& rhs)
	{
		this->name=rhs.name;
	}

	Customer& operator=(const Customer& rhs)
	{
		if(this==&rhs) 
			return *this;

		this->name=rhs.name;
		return *this;
	}
private:
	std::string name;
};

class PriorityCustomer:public Customer
{
public:
	PriorityCustomer(const PriorityCustomer& rhs)
		:Customer(rhs),
		priority(rhs.priority)
	{

	}
	PriorityCustomer& operator=(const PriorityCustomer& rhs)
	{
		Customer::operator=(rhs);
		priority=rhs.priority;
		return *this;
	}
private:
	int priority;
};


另外,不要尝试在某个拷贝函数实现另一个拷贝函数。应该将重复代码部分放进第三个函数,供拷贝构造函数和赋值运算符调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值