话说智能指针发展之路

从RAII说起

教科书里关于“动态创建内存”经常会提醒你,new一定要搭配delete来使用,并且delete掉一个指针之后,最好马上将其赋值为NULL(避免使用悬垂指针)。

这么麻烦,于是乎,这个世界变成11派人:
一派人勤勤恳恳按照教科书的说法做,时刻小心翼翼,苦逼连连;
一派人忘记教科书的教导,随便乱来,搞得代码处处bug,后期维护骂声连连;
最后一派人想了更轻松的办法来管理动态申请的内存,然后悠闲唱着小曲喝着茶~

(注:应该没人看不懂11是怎么来的……就是十进制的3的二进制形式)

正式介绍开始,RAII全称为Resource Acquisition Is Initialization,引用维基百科的解释:

RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

更详细的阐释可以参考《Effective C++》(第三版,条款13:以对象管理资源)。

众所周知,分配在栈上的对象在退出作用域时会自动销毁,所以需要关注的是动态申请内存的做法。用原始指针,正如一开始所说的,很麻烦,最后一派的人就根据RAII思想的指引,创造了智能指针

随着编译器对智能指针的支持,对于C++程序猿来说应该是一件很值得高兴的事,引用一句话:

智能指针的出现,给不支持垃圾回收机制的C++带来了一丝曙光。

声明

本文为了突出对比表现各种智能智能的优劣,所以虚构了一个“发展之路”,原创者的想法不一定真的如我所说~

auto_ptr

先看一个实例感受一下auto_ptr相较于原始指针的方便之处:

#include <iostream>
#include <string>
#include <memory>
using namespace std;


int main() {
    auto_ptr<string> ps1(new string("Hello, auto_ptr!"));
    cout << "The content is: " << *ps1 << endl;

    return 0;
}

是不是实现了上面所说的“自动管理动态内存”的目标呢?
不需要手动释放,自动析构!!!

想要了解更多操作的,可以看一下下图所示的auto_ptr的接口说明
auto_ptr

但是,在C++11标准中,auto_ptr已经被弃用了(虽然为了向前兼容,还原封不动保留着,但是有了更好的工具,为何不用呢?)。
问题来了,为什么它这么好,还会被抛弃呢?

wiki说了,auto_ptr是“复制语义”,这个名词不懂无所谓,举个例子就知道了:

#include <iostream>
#include <string>
#include <memory>
using namespace std;


int main() {
    auto_ptr<string> ps1(new string("Hello, auto_ptr!"));
    auto_ptr<string> ps2;
    ps2 = ps1;

    //【E1】下面这行注释掉才可正确运行,原因见下文分析
    //cout << "ps1: " << *ps1 << endl;
    cout << "ps2: " << *ps2 << endl;

    return 0;
}

简单理解的话,可以认为是,auto_ptr是支持复制的(不信回头去看上面的auto_ptr接口说明里的constructor项),一旦允许复制,就很容易发现一个问题——若两个auto_ptr对象都包含了同一个指针(即指向同个对象,同一块内存),那么当它们都析构的时候,同一个对象就会被析构两次!!!运行出错了吧?

解决方法是很简单了,auto_ptr的做法是:当发生复制/赋值时,把被复制/赋值的对象内部的指针值赋值为NULL,这样始终只有一个auto_ptr对象指向同一个对象,所以保证了不会多次析构!

由此,关于上述代码【E1】处的原因解析是:
运行到这里会出错,因为ps1内部的指针值经过赋值运算后&#x

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值