类的拷贝控制

类的行为:

  1. 像值
  2. 像指针
  • 类的行为像值,意味着它应该也有自己的状态。当我们拷贝一个像值的对象时,副本和原对象时完全独立的。改变副本不会对原对象有任何影响,反之亦然。
  • 行为像指针的类则共享状态。当我们拷贝一个这种类的对象时,副本和原对象使用相同的底层数据。改变副本也会改变原对象,反之亦然。

行为像值的类

//HasPtrAsVal.h
class HasPtrAsVal
{
public:
	HasPtrAsVal(const std::string &s = std::string()) :ps(new std::string(s)), i(0)
	{
	}
	
	//对ps 指向的string,每个HasPtrVal对象都有自己的拷贝
	HasPtrAsVal(const HasPtrAsVal &p) :ps(new std::string(*p.ps)), i(p.i)
	{

	}

	HasPtrAsVal& operator=(const HasPtrAsVal &);
	~HasPtrAsVal()
	{
		delete ps;
	}

private:
	std::string *ps;
	int i;
};

//HasPtrAsVal.cpp
//当编写一个赋值运算符时,一个好的模式是先将右侧运算对象拷贝到一个局部临时对象中。
//当拷贝完成后,销毁左侧运算对象的现有成员就是安全的了。
//一旦左侧运算对象的资源被销毁,就只剩下将数据从临时对象拷贝到左侧运算对象的成员中了。 HasPtrAsVal& HasPtrAsVal::operator=(const HasPtrAsVal &rhs) { auto newp = new string(*rhs.ps);//拷贝底层string delete ps;//释放旧内存 ps = newp;//从右侧运算对象拷贝数据到本对象 i = rhs.i; return *this; }

  

行为像指针的类

令一个类展现类似指针的行为的最好方法是使用shared_ptr来管理类中的资源。

但是,有时我们希望直接管理资源。在这种情况下,引用计数就相当有用。用它来记录有多少用户共享它指向的对象,当没有用户使用对象时,释放资源。

//HasPtrAsPtr.h
class HasPtrAsPtr
{
public:
	//构造函数分配新的string和新的计数器,将计数器置1
	HasPtrAsPtr(const std::string& s = std::string()) :ps(new std::string(s)), i(0), use(new std::size_t(1)) 
	{
	};

	HasPtrAsPtr(const HasPtrAsPtr &p) :ps(p.ps), i(p.i), use(p.use)
	{
		++*use;//拷贝时计数器+1
	}

	HasPtrAsPtr& operator=(const HasPtrAsPtr&);
	~HasPtrAsPtr();

private:
	std::string *ps;
	int i;
	std::size_t *use;	//用来记录有多少个对象共享*ps的成员
};


//HasPtrAsPtr.cpp
//拷贝赋值运算符执行类似拷贝构造函数和析构函数的工作
//1、它必须递增右侧运算对象的引用计数(即,拷贝构造函数)
//2、并递减左侧运算对象的引用计数,在必要时释放使用的内存(即,析构函数的工作) HasPtrAsPtr & HasPtrAsPtr::operator=(const HasPtrAsPtr & rhs) { // TODO: 在此处插入 return 语句 ++*rhs.use; //递增右侧运算对象的引用计数 if (--*use == 0)//递减本对象的引用计数 { delete ps;//如果没有其他用户,释放本对象分配的成员 delete use; } ps = rhs.ps;//将数据从rhs拷贝到本对象 i = rhs.i; use = rhs.use; return *this; } HasPtrAsPtr::~HasPtrAsPtr() { if (--*use == 0)//如果引用计数变为0 { delete ps;//释放string 内存 delete use;//释放计数器内存 } }

  

  

原文地址:https://www.cnblogs.com/zhehan54/p/5389308.html