码迷,mamicode.com
首页 > 编程语言 > 详细

【足迹C++primer】43、拷贝控制和资源管理

时间:2014-07-13 13:42:44      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:析构函数      拷贝控制   内存资源管理   

拷贝控制和资源管理

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
}

定义一个使用引用计数的类

<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;
}

PS:这期还是没有效果图,因为我都没有在主函数中加相应的函数,不过无所谓啦,代码是没错的,能通过编译,至少没有语法错误,还有就是定义类,应该不会出现逻辑错误吧!!!嘿嘿,其实这节应该可以9点左右就发出来的,但是你能想象我9点左右出去打印照片吗????
打印 苍老师的照片!!!苍老师!!!没错就是苍井空。。。。打印室的老板盯着我看了半天,这家伙干嘛。。。。

【足迹C++primer】43、拷贝控制和资源管理,布布扣,bubuko.com

【足迹C++primer】43、拷贝控制和资源管理

标签:析构函数      拷贝控制   内存资源管理   

原文地址:http://blog.csdn.net/cutter_point/article/details/37736641

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!