c++智能指针

定义:智能指针是行为类似指针的类对象,但这种对象还有一些其他的功能。

为什么要有智能指针?

🌰案例说明1:

void test(std::string & str){
    std::string * ps = new std::string(str);
    return ;
}

通过以上案例可以发现,在函数内new了一个string对象后并没有进行delete操作,当我们大量地调用test()函数时会造成大量的内存泄漏。这种情况可能是因为我们忘了在return前加上delete ps;这句话,但是如果我们总是记住加delete但仍会出现一些意想不到的情况导致没有执行delete从发引发内存泄漏,如下:

🌰案例说明2:

void test(std::string & str){
    std::string * ps = new std::string(str);
    if(weird_thing()))
        throw exception();
    delete ps;
    return ;
}

从以上案例我们可以发现当出现异常时,delete将不被执行,因此同样会导致内存泄漏。

因此,我们想如果ps有一个析构函数,在ps过期时会及时释放它指向的内存这该多好啊,但问题是ps仅是一个常规指针,不是有析构函数的类对象,因此就有了auto_ptr、unique_ptr、shared_ptr等类似指针的类对象的出现。

#include <memory>
void test(std::string & str){
    std::auto_ptr(std::string) ps (new std::string(str));
    if(weird_thing()))
        throw exception();
    return ;
}

以上是将普通的ps指针替换成auto_ptr智能指针的案例,我们可以省去delete操作,并且可以确保在ps指针在生命周期结束后自动调用析构函数释放内存,避免内存泄漏。

智能指针的特性:

  • 智能指针对象的很多方面都类似于常规指针。例如,如果ps是一个智能指针对象,则可以对它执行解除引用操作(*ps)、用它访问结构成员(ps->puffIndex)、将它赋给指向同类型的常规指针等。

1.为什么要放弃auto_ptr?

auto_ptr<string> ps(new string("I love shushu."));
auto_ptr<string> m_ps;
m_ps = ps;

如果ps与m_ps都是常规指针,则两个指针将指向同一个string对象,这是显然不可以接受的,因为当程序将试图删除同一个对象两次,当然避免的方法也有很多种:

  • 定义赋值运算符,使其执行深拷贝,这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本。
  • 建立所有权概念,对于特定的丢向,只能有一个智能指针可以拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象。然后让赋值操作转让所有权,这就是用于auto_ptr和unique_ptr的策略。
  • 创建更加智能的指针类对象,跟踪引用特定对象的智能指针数。这称为引用计数,例如每当赋值时,计数将加1,而指针国企时,计数将减1.仅当最后一个指针过期时,才调用delete。这就是shared_ptr采用的策略。

以下案例将不适用于auto_ptr:

void test(){
    auto_ptr<string> fruit[3] = {
        auto_ptr<string> (new string("apple")),
        auto_ptr<string> (new string("banana")),
        auto_ptr<string> (new string("orange"))    
    };
    auto_ptr<string> pf;
    pf = fruit[2];//此时fruit[2]将丧失所有权,转移给pf
    for(int i = 0; i < 3; i++)
        cout<<*fruit[i]<<endl;
}

以上代码的循环输出仅会输出:apple banana,然后就会提示Sementation fault(core dumped)错误。这是因为fruit[2]将所有权转让后,仍用它来访问该对象,却发现此时已经是一个空指针了。但如果将智能指针替换成shared_ptr即可解决该问题。因为shared_ptr采用引用计数,当pf与fruit[2]指向一个对象时,引用计数从1增加到2,因此会使pf先调用析构函数,将引用计数降低到1,然后将shared_ptr数组的成员书房,对fruit[2]调用析构函数,再将引用计数降为0,释放所分配的空间。

2.为什么unique_ptr优于auto_ptr?

根据上面的代码我们可知,当pf接管所有权后,如果程序随后再试图使用fruit[2]则会报错,因为pf无法指向有效的数据。但如果把auto_ptr换成unique_ptr后,pf仍会接管所有权,但在编译过程中,编译器就会认定pf=fruit[2]是非法的,从而避免了fruit[2]不再指向有效数据的问题。因此unique_ptr比auto_ptr更安全主要体现在编译阶段错误比潜在的程序崩溃更安全

(warning:unique_ptr却允许赋给一个临时右值。)

unique_ptr还有另一个优点:它拥有一个可用于数组的变体,即有使用new[]和delete[]的版本。而auto_ptr和shared_ptr仅能使用New分配内存,不可用new[]。

参考文献

《Effective C++(第三版)》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值