C++中以对象管理资源<auto_ptr>(13)---《Effective C++》

条款13:以对象管理资源

我们为什么要以对象管理资源呢?有什么用处呢?在回答这个问题之前先来看看如下代码:

class Investment{...};
Investment* createInvestment();
void f(){
    Investment* pInv=createInvestment();
    ...
    delete pInv;
}

可以看到,上述代码中,如果…中代码提前return掉,或者…中发生异常,甚至createInvestment()中由于循环中的goto语句或者continue语句的设计异常,这样都将导致delete pInv语句不会被执行,这样将引发内存泄露等一系列问题。

为了解决上述问题,我们需要将资源放入对象内,当控制流离开f函数时候,对象那个的析构函数自动释放资源,即
1)获得资源后立即放进资源管理对象中;
2)管理对象运用析构函数确保资源被释放,即不论何时,控制流离开区块时候,其析构函数会自动调用,于是资源被释放掉!

这样的解决思路是不是简洁明了呀!
我们通常用到的有两种这样的对象,可以在控制流离开区块或者函数时候被释放,包括auto_ptr和auto_ptrs。
1)auto_ptr是个“类指针”对象,也就是所谓的“智能指针”,气息狗函数自动对其所指的对象那个调用delete,请看如下代码示意:

void f(){
    std::auto_ptr<Investment> pInv(createInvestment());
    ...
}

这样就可以使得该指针在离开作用域时候自动调用delete,自动调用析构函数!
PS:auto_ptr被销毁的时候会自动删除他所指向的对象,因此注意不要让多个auto_ptr对象指向同一个对象,如果这样做的话,对象会被删除一次以上,而这样会使得你的程序出现“未定义行为”的错误!为了预防这个问题,C++的设计者为auto_ptr设计有一个不寻常的性质,若通过copy构造函数或者copy assignment操作符赋值它们,它们会变为null,而复制所得的函数将取得资源的唯一所有权!具体参看如下代码:

#include <iostream>
#include <cstring>
#include <string>
using namespace std;
class Hello{
public:
    Hello(){

    }
    Hello(int x, int y) :x(x), y(y){

    }
    Hello(Hello& h){
        this->x = h.x;
        this->y = h.y;
    }
    Hello& operator=(const Hello& h){
        this->x = h.x;
        this->y = h.y;
        return *this;
    }
    friend ostream& operator<<(ostream& os, Hello& hel){
        os << hel.x << " " << hel.y << endl;
        return os;
    }
    void show(){
        cout << x << " " << y << endl; 
    }

    friend Hello* createHello(Hello& hello){
        try{
            Hello *hel = new Hello();
            hel->x = hello.x;
            hel->y = hello.y;
            return hel;
        }
        catch (exception &e){
            cout << e.what() << endl;
        }
        return NULL;
    }
    ~Hello(){

    }
private:
    int x;
    int y;
};

/*int* h1(){
    int m = 9;
    return &m;
}*/
int main(){
    Hello hel(1, 2);
    auto_ptr<Hello> hel_ptr(createHello(hel));

    auto_ptr<Hello> hel_ptr2(hel_ptr);
    cout << *hel_ptr2<< endl;
    hel_ptr = hel_ptr2;
    cout << *hel_ptr << endl;
}

这里我们输出*hel_ptr2和*hel_ptr的值,注意它们都是通过别的制针值赋值的指针。
此时运行结果为:
这里写图片描述
如果我们将代码改为如下(PS:为了验证auto_ptr的copy函数的奇特属性)

#include <iostream>
#include <cstring>
#include <string>
using namespace std;
class Hello{
public:
    Hello(){

    }
    Hello(int x, int y) :x(x), y(y){

    }
    Hello(Hello& h){
        this->x = h.x;
        this->y = h.y;
    }
    Hello& operator=(const Hello& h){
        this->x = h.x;
        this->y = h.y;
        return *this;
    }
    friend ostream& operator<<(ostream& os, Hello& hel){
        os << hel.x << " " << hel.y << endl;
        return os;
    }
    void show(){
        cout << x << " " << y << endl; 
    }

    friend Hello* createHello(Hello& hello){
        try{
            Hello *hel = new Hello();
            hel->x = hello.x;
            hel->y = hello.y;
            return hel;
        }
        catch (exception &e){
            cout << e.what() << endl;
        }
        return NULL;
    }
    ~Hello(){

    }
private:
    int x;
    int y;
};

/*int* h1(){
    int m = 9;
    return &m;
}*/
int main(){
    Hello hel(1, 2);
    auto_ptr<Hello> hel_ptr(createHello(hel));

    auto_ptr<Hello> hel_ptr2(hel_ptr);
    cout << *hel_ptr<< endl;
    hel_ptr = hel_ptr2;
    cout << *hel_ptr2 << endl;
}

这里我们输出*hel_ptr和*hel_ptr2的值,注意它们都是被赋值的指针。
运行结果为:
这里写图片描述
可以发现,auto_ptr通过copying函数复制时候,它们会变为NULL,复制的指针将获得取得资源的唯一特权,简单理解就是在auto_ptr通过copying函数赋值时,左值获得资源,右值置为NULL!

2)auto_ptr的引用方案是“引用技术型智慧指针(reference-counting smart pointer;RCSP)”,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源,RCSPs提供的行为类似垃圾回收,但无法打破环状引用,参看如下代码:

void f(){
    ...
    std::trl::shared_ptr<Investment> pInv(createInvestment());
    std::trl::shared_ptr<Investment> pInv2(pInv);//pInv和pInv2指向同一个对象
    pInv=pInv2;//pInv和pInv2指向同一个对象
    ...
}

需要注意的是,auto_ptr和trl::shared_ptr的析构函数做的是delete动作而不是delete[]动作,那意味着在动态分配时候得到的array身上使用auto_ptr或者trl::shared_ptr是个馊主意,但是仍然可以通过编译,运行报错。

总结:
1)为了防止资源泄露,请调用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源;
2)通常我们使用auto_ptr和shared_ptr进行对象管理资源,但需要注意auto_ptr的copying函数的奇葩特性哈!

PS:函数createInvestment中返回指针一般超级容易忘记使用delete进行资源删除,因此我们需要对象管理这些资源,这里我们介绍了std::auto_ptr和std::trl::shared_ptr两种对象为例,做了讲解,大家也可以试试其他对象管理资源哈!

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值