37.拷贝控制和资源管理

版权声明:本博客为记录本人学习过程而开,内容大多从网上学习与整理所得,若侵权请告知! https://blog.csdn.net/Fly_as_tadpole/article/details/83096864

类中只要有一个成员不可能拷贝、赋值、析构的话,类的合成拷贝控制成员就被定义为delete

在新标准发布之前,要想阻止拷贝,类将拷贝构造函数和拷贝赋值运算符声明为private只是声明,没有给出定义。

这样一来,试图拷贝对象的用户代码在编译阶段就会被标记为错误。成员函数或者友元函数中的拷贝操作将会导致链接时错误。


定义行为像值的类

当我们拷贝一个像值的对象时,副本和原对象是完全独立的。改变副本不会对原对象有任何影响。


using namespace std;

class has
{
	string* str;
	int i;
public:
	has(const string& s = string()) :str(new string (s)), i(0) {}
	has(const has & h) :str(new string(*h.str)), i(h.i) {}
	has& operator=(const has &);
	~has() { delete str; }

};

has& has::operator=(const has& hs)
{
	string* tmp = new string(*hs.str);
	delete str;
	str = tmp;
	i = hs.i;
	return *this;
}

当我们编写赋值运算符的时候,有两点需要记住:

1)如果将一个对象赋值给对象本身的话,赋值运算符必须能够正确工作;

2)大多数的赋值运算符组合了拷贝构造函数和析构函数的工作。

当你在编写一个赋值运算符的时候,一个好的模式是:

先将等号右侧的对象拷贝到一个临时的对象中。当拷贝完成之后,销毁左侧的对象的现有成员就是安全的了。一旦左侧的运算对象的资源被销毁的话,就只剩下将临时对象的资源拷贝到左侧的运算对象的成员之中。


定义行为像指针的类

采用计数器机制,对象的拷贝不会改变底层的结构,也就是说。当一个对象,另一个对象随之改变。

using namespace std;

class has
{
	string* str;
	int i;
	size_t* use;
public:
	has(const string & s = string()) :str(new string(s)), i(0), use(new size_t(1)) {}
	has(const has& hs) :str(hs.str), i(hs.i), use(hs.use) {}
	has& operator=(const has& h);
	~has();
};


has& has::operator=(const has &h)
{
	++*h.use;
	if (--*use == 0)
	{
		delete str;
		delete use;
	}
	str = h.str;
	i = h.i;
	use = h.use;
	return *this;

}

has::~has()
{
	if (--*use == 0)
	{
		delete str;
		delete use;
	}
}

猜你喜欢

转载自blog.csdn.net/Fly_as_tadpole/article/details/83096864