class HasPtr { public: HasPtr(const string &s=string()):ps(new string(s)), i(0){} //对ps指向的string,每个HasPtr对象都有自己的拷贝 HasPtr(const HasPtr &p):ps(new string(*p.ps)), i(p.i) {} HasPtr & operator=(const HasPtr &); ~HasPtr() {delete ps;} private: string *ps; int i; };
HasPtr& HasPtr::operator=(const HasPtr &rhs) { auto newp=new string(*rhs.ps); //拷贝底层string delete ps; //释放旧内存 ps=newp; //从右侧运算对象拷贝数据到本对象 i=rhs.i; return *this; //返回本对象 }
HasPtr& HasPtr::operator=(const HasPtr &rhs) { delete ps; //释放对象指向string //如果rhs和*this是同一个人对象,我们就将从已释放的内存中拷贝数据! ps=new string(*(rhs.ps)); i=rhs.i; return *this; }
void fun1() { HasPtr p1("Hiya!"); HasPtr p2(p1); //p1和p2指向相同的string HasPtr p3(p1); //p1、p2、p3都指向相同的string }
<pre name="code" class="cpp">class HasPtr2 { public: //构造函数分配新的string和新的计数器,将计数器置为1 HasPtr2(const string &s):ps2(new string(s)), i2(0), use(new size_t(1)){} //拷贝构造函数拷贝所有三个数据成员,并递增计数器 HasPtr2(const HasPtr2 &p):ps2(p.ps2), i2(p.i2), use(p.use) {++*use;} HasPtr2 & operator=(const HasPtr2 &); ~HasPtr2(); private: string *ps2; int i2; size_t *use; //记录有多少个对象共享*ps的成员 }; HasPtr2::~HasPtr2() { if(--*use==0) //调用析构函数就要-- {//如果引用计数变为0 delete ps2; //释放string内存 delete use; //释放计数器内存 } } HasPtr2 & HasPtr2::operator=(const HasPtr2 &rhs) { ++*rhs.use; //拷贝一个,那就递增一个计数 if(--*use == 0) //递减本对象的引用计数 { delete ps2; //如果没有其他用户了 delete use; //释放分配的成员 } /* 上面这个if应该如何去看呢? rhs拷贝给一个对象的时候,指向rhs的对象就会多一个所以++ 然后拷贝的对象,得到新值就会把原来的值去掉所以会-- 然后看是不是最后一个是的话直接销毁,不是那就不管--就可以了 */ ps2=rhs.ps2; i2=rhs.i2; use=rhs.use; return *this; //返回本对象 }
/** * 功能:拷贝控制和资源管理 * 时间:2014年7月13日08:54:26 * 作者:cutter_point */ #include<iostream> #include<string> using namespace std; /************************************** 13.2.1行为像值的类 **************************************/ /* *定义一个拷贝构造函数,完成string的拷贝,而不是拷贝指针 *定义一个析构函数来释放string *定义一个拷贝赋值运算符来释放对象当前的string,并从右侧运算对象拷贝string */ class HasPtr { public: HasPtr(const string &s=string()):ps(new string(s)), i(0){} //对ps指向的string,每个HasPtr对象都有自己的拷贝 HasPtr(const HasPtr &p):ps(new string(*p.ps)), i(p.i) {} HasPtr & operator=(const HasPtr &); ~HasPtr() {delete ps;} private: string *ps; int i; }; /** 类值拷贝赋值运算符 */ HasPtr& HasPtr::operator=(const HasPtr &rhs) { auto newp=new string(*rhs.ps); //拷贝底层string delete ps; //释放旧内存 ps=newp; //从右侧运算对象拷贝数据到本对象 i=rhs.i; return *this; //返回本对象 } //这里有一个错误的示范!! /* HasPtr& HasPtr::operator=(const HasPtr &rhs) { delete ps; //释放对象指向string //如果rhs和*this是同一个人对象,我们就将从已释放的内存中拷贝数据! ps=new string(*(rhs.ps)); i=rhs.i; return *this; } */ //看出来了么,这里new string(*(rhs.ps))里面的ps是已经释放了的,也就是把释放过的内存拿来赋值,显然是未定义的 /************************************** 13.2.2定义行为像指针的类 **************************************/ /* 令一个类展现类似指针的行为的最好的方法是使用shared_ptr来管理类中的资源 但是,有时候我们希望直接管理资源。在这种情况下,使用引用计数 */ /** 引用计数 */ void fun1() { HasPtr p1("Hiya!"); HasPtr p2(p1); //p1和p2指向相同的string HasPtr p3(p1); //p1、p2、p3都指向相同的string } /** 定义一个使用引用计数的类 */ class HasPtr2 { public: //构造函数分配新的string和新的计数器,将计数器置为1 HasPtr2(const string &s):ps2(new string(s)), i2(0), use(new size_t(1)){} //拷贝构造函数拷贝所有三个数据成员,并递增计数器 HasPtr2(const HasPtr2 &p):ps2(p.ps2), i2(p.i2), use(p.use) {++*use;} HasPtr2 & operator=(const HasPtr2 &); ~HasPtr2(); private: string *ps2; int i2; size_t *use; //记录有多少个对象共享*ps的成员 }; HasPtr2::~HasPtr2() { if(--*use==0) //调用析构函数就要-- {//如果引用计数变为0 delete ps2; //释放string内存 delete use; //释放计数器内存 } } HasPtr2 & HasPtr2::operator=(const HasPtr2 &rhs) { ++*rhs.use; //拷贝一个,那就递增一个计数 if(--*use == 0) //递减本对象的引用计数 { delete ps2; //如果没有其他用户了 delete use; //释放分配的成员 } /* 上面这个if应该如何去看呢? rhs拷贝给一个对象的时候,指向rhs的对象就会多一个所以++ 然后拷贝的对象,得到新值就会把原来的值去掉所以会-- 然后看是不是最后一个是的话直接销毁,不是那就不管--就可以了 */ ps2=rhs.ps2; i2=rhs.i2; use=rhs.use; return *this; //返回本对象 } int main() { return 0; }
【足迹C++primer】43、拷贝控制和资源管理,布布扣,bubuko.com
原文地址:http://blog.csdn.net/cutter_point/article/details/37736641