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

拷贝控制和资源管理

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、拷贝控制和资源管理

时间: 2024-11-05 18:42:24

【足迹C++primer】43、拷贝控制和资源管理的相关文章

【C++ Primer 第13章】2. 拷贝控制和资源管理

拷贝控制和资源管理 • 类的行为像一个值.意味着它应该有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响. • 行为像指针的类则共享状态.当我们拷贝一个这种类的对象时,副本和原对象使用相同的底层数据,改变副本也会改变原对象. 13.2节练习 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 class HasPtr { 6 public: 7 HasP

拷贝控制和资源管理

拷贝控制和资源管理 通常,管理类外资源的类必须定义拷贝控制成员.有两种选择:可以定义拷贝操作,使类的行为看起来像一个值或者像一个指针. 类的行为像一个值,意味着它应该也有自己的状态.当我们拷贝一个像值的对象时,副本和原对象时完全独立的.改变副本不会对原对象由任何影响,反之亦然. 行为像指针的类则共享状态.当我们拷贝一个这种类的对象时,副本和原对象使用相同的底层数据.改变副本也会改变原对象,反之亦然. IO类型和unique_ptr不允许拷贝或赋值,因此它们的行为既不像值也不像指针. 赋值运算符

拷贝控制2(拷贝控制和资源管理/交换操作)

为了定义拷贝构造函数和拷贝赋值运算符,我们首先必须确认此类型对象的拷贝语义.通常可以定义拷贝操作,使类的行为看起来像一个值或者像一个指针(即所谓的深拷贝和浅拷贝) 类的行为像一个值,意味着它应该也有自己的状态.当我们拷贝一个像值的对象时,副本和原对象是完全独立的.改变副本不会对原对象有任何影响,反之亦然 行为像指针的类则共享状态.当我们拷贝一个这种类的对象时,副本和原对象使用相同的底层数据.改变副本也会改变原对象,反之亦然 在我们使用过的标准库类中,标准库容器和 string 类的行为像一个值.

C++ Primer 笔记——拷贝控制

1.如果构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是引用类型(否则会无限循环的调用拷贝构造函数). 2.如果没有为一个类定义拷贝构造函数,编译器会为我们定义一个合成拷贝构造函数.与合成默认构造函数不同,即使我们定义了其他的构造函数,编译器也会为我们合成一个拷贝构造函数. 3.合成的拷贝构造函数会将其参数的成员逐个拷贝到正在创建的对象中(除了static成员).对于类类型的成员,会使用其拷贝构造函数来拷贝,虽然我们不能

【C++ Primer】拷贝控制

十三.复制控制 1. 复制构造函数 类中的成员函数都默觉得inline类型.所以即使在类定义体内的函数声明显示定义为inline类型,在进行函数定义时也可以将inline进行省略. // 复制构造函数应该为常量引用类型,假设同意传值參数会造成无限循环调用从而导致内存溢出. CopyConstruct(const CopyConstruct& a){value = a.value;} 复制构造函数可用于初始化顺序容器中的元素,如vector<string> svec(5); 这样的方式使

13.2:拷贝控制和资源管理

两种选择: 类的行为像一个值:有自己的状态,拷贝一个像值的对象时,副本和原对象是完全独立的.改变副本不会改变原对象. 类的行为像一个指针:类是共享状态,当拷贝这个对象时,原对象和副本对象使用相同的底层数据,改变副本也会改变原对象. 1.行为像值的类 拷贝对象,而不是拷贝指针. 代码如下: class HasPtr{ public: HasPtr(const string &s = string()):ps(new string(s)), i(0) {} //对ps指向的string,每个HasP

《C++primer(第五版)》学习之路-第十三章:拷贝控制

[ 声明:版权所有,转载请标明出处,请勿用于商业用途.  联系信箱:[email protected]] 13.1 拷贝.赋值与销毁 1.当定义一个类时,我们显式地或隐式地指定在此类型的对象拷贝.移动.赋值和销毁时做什么.一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数. 2.在一个构造函数中,成员的初始化是在函数体执行之前完成的,且按照它们在类中出现的顺序进行初始化.在一个析构函数中,首先执行函数体,然后销毁成员.成员按

拷贝控制

当定义一个类时,我们显式地或隐式地指定在此类型的对象拷贝.移动.赋值和销毁时做什么.一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数(copy constructor).拷贝赋值运算符(copy-assignment operator).移动构造函数(move constructor).移动赋值运算符(move-assignment operator)和析构函数(destructor).拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么.拷贝和移动赋值运算符定义

C++11(12):拷贝控制

拷贝构造函数的第一个参数必须是引用类型,此参数几乎总是const的引用.拷贝构造函数在几种情况下会隐式地使用.因此,拷贝构造函数不应该是explicit的 即使我们定义了其他构造函数,在没有拷贝构造函数时,编辑器也会为我们合成的.编辑器从给定对象中依次将每个非static成员拷贝到创建的对象中.每个成员决定了它使用何种方式进行拷贝.类调用拷贝构造函数,数组逐个拷贝,内置类型直接拷贝 string dots(10,'.')  //直接初始化 string noll_book="999999&quo