<C++学习篇>C++中的智能指针auto_ptr,unique_otr,shared_ptr

在C++中为了更好的管理动态内存,C++98~C++11引入智能指针 auto_ptr,unique_otr,shared_ptr
与常规指针相比,智能指针在过期之后会自动销毁所分配的内存空间.
提到内存空间,有一些概念:

名称存放方式及内容
由程序员分配和释放
保存局部变量级函数参数等,系统分配和释放
常量区(全局区))系统释放
代码区存放函数等二进制代码

例如:
引用网上的解释 :

int a=0;//全局初始化区
char *p;//全局未初始化区
int main()
{
int b;//栈
char s[]="abc";//栈
char *p2;//栈
char *p3="123456";//p3在栈,"123456"在常量区
static int c=0;//全局初始化区
p1=(char*)malloc(10);//分配的内存在堆区
return 0;
}

再看代码

void remodel(std::string & str)
{
    std::string *ps=new std::string(str);//这里new 分配出来的内存在堆上
    ...
    str=ps;
    return ;//函数执行到这里,指针ps保存的地址值被清掉,地址所指的堆内存却未处理,导致内存泄露
    //应该在return之前加上 delete ps;语句
}

这段代码,我们自己new开辟的内存还要自己手动释放,但很多时候,忘了,导致内存泄露
引入智能指针,就是避免了我们忘记释放内存而导致内存泄露

智能指针其实是个类对象,只是行为类似指针
使用智能指针要包含头文件:

#include<memory>
  1. auto_ptr
  2. shared_ptr
  3. unique_ptr
//auto_ptr.cpp
#include<iostream>
#include<memory>
#include<string>

class Report
{
    private:
        std::string str;
    public:
    Report(const std::string s):str(s)
        {std::cout<<"Object be created!";}
    ~Report(){std::cout<<"Object deleted!";}
    void comment() const {std::cout<<str<<"\n";}
};

int main()
{
    {
        std::auto_ptr<Report>ps (new Report("using auto_ptr"));
        ps->comment();
    }//ps 有效期就在这个代码块里,出了该范围就过期,auto_ptr帮我们自动销毁ps所指内存
    {
        std::shared_ptr<Report>ps (new Report("using shared_ptr"));
        ps->comment();
    }//ps 有效期就在这个代码块里,出了该范围就过期,shared_ptr帮我们自动销毁ps所指内存
    {
        std::unique_ptr<Report>ps (new Report("using unique_ptr"));
        ps->comment();
    }//ps 有效期就在这个代码块里,出了该范围就过期,unique_ptr帮我们自动销毁ps所指内存
return 0;
}

输出结果:
Object created!
using auto_ptr
Object delete!
Object created!
using shared_ptr
Object delete!
Object created!
using unique_ptr
Object delete!
但c++11中 auto_ptr被摒弃,因为auto_ptr同类指针之间相互赋值,产生了空指针,使用空指针,会导致问题!(也有说,两个指针指向同一个对象,智能指针释放内存空间时,该空间被连续释放两次)
代码如下:

auto_ptr<string>ps (new string(" 哈哈哈哈"));
auto_ptr<string> ps1;
ps1=ps;//ps 失去新建对象的所有权,ps指的对象被ps1剥夺,ps变成空指针,ps1 指向new 出来的"哈哈哈哈"
std::cout<<ps<<"\n";
//再次使用到ps指针时会报异常,Sementation 11(g++ 编译得出))

给出C++ primer plus上的源代码

//fowl.cpp -- auto_ptr a poor choice 
#include<iostream>
#include<string>
#include<memory>

int main()
{
    using namespace std;
   auto_ptr<string> films[5]=
    {
        auto_ptr<string>(new string("Fowl Balls")),
        auto_ptr<string>(new string("Duck Walks")),
        auto_ptr<string>(new string("Chicken Runs")),
        auto_ptr<string>(new string("Turkey Errors")),
        auto_ptr<string>(new string("Goose Eggs"))
    };

    auto_ptr<string> pwin;
    pwin=films[2];//films[2]失去对"chicken runs" 所有权
    cout<<"The nominees for best avian baseball film are \n";
    for(int i=0;i<5;i++)
        cout<<*films[i]<<endl;//当然了,当i=2 ,循环停止,因为会报异常:Sementation 11(具体因系统而异) ,因为films[2] 变成空指针了
    cout<<"The winner is :"<<*pwin<<"!\n";
    cin.get();
    return 0;
}

运行报错:
window下直接报错
将auto_ptr改为shared_ptr
运行ok:
ok
因为使用shared_ptr 后pwin和films[2]指向的是同一个对象,引用计数变为2,pwin调用后销毁,计数变为1,films[2]数组再次调用销毁,计数变为0,空间真正被释放
那么换为uinque_ptr会怎样?
直接会在编译是报错,
编译阶段报错
unique_ptr比auto_ptr 更安全

unique_ptr 指的是一个对象,只能有一个智能指针拥有它(空间和时间上).该指针会在编译阶段判断,有异常不会在运行阶段爆发,所以说更安全
特别指出的是,如果有一个智能指针所指的对象,在该对象赋给另一个智能指针时,前一个智能指针已经被销毁,那么也是可以的,例如:

unique_ptr<string> demo(string &str)
{
    unique_ptr<string> temp (new string(str));
    return temp;
}

unique_ptr<string> ps;
ps=demo("UNIQUE_PTR TEST");
//demo() 返回一个临时unique_ptr ,然后ps剥夺temp 指针所指的对象所有权,随后temp被销毁,不复存在,没有机会使用它访问无效数据,这就是时间上允许两个指针都指向同一对象.

若是temp会和ps共存一段时间,那么是不被允许的
例如:
unique_ptr<string>temp(new string("Hi ho!"));
unique_ptr<string>ps;
ps=temp;//不被允许,temp(剥夺所有权后为空指针)会同时存在一段时间,有可能会被使用
//可以使用std::move()更改,ok

unique_ptr<string> ps1;
ps1=unique_ptr<string>(new string("hah")));//允许,  调用unique_ptr<string>构造函数创建一个临时变量,被剥夺所有权后被销毁

ps=temp;//不被允许,temp(剥夺所有权后为空指针)会同时存在一段时间,有可能会被使用但可以使用std::move()更改,ok    ps=move(temp);

更改前面代码:

    int main()
{
    using namespace std;
    unique_ptr<string> films[5]=
    {
        unique_ptr<string>(new string("Fowl Balls")),
        unique_ptr<string>(new string("Duck Walks")),
        unique_ptr<string>(new string("Chicken Runs")),
        unique_ptr<string>(new string("Turkey Errors")),
        unique_ptr<string>(new string("Goose Eggs"))
    };

    unique_ptr<string> pwin;
    pwin=move(films[2]);//films[2]失去对"chicken runs" 所有权
    cout<<"The nominees for best avian baseball film are \n";
    for(int i=0;i<5;i++)
    {
        if(i==2)
        continue;//当i=2 ,循环停止,因为会报异常:Sementation 11(具体因系统而异) ,因为films[2] 变成空指针,所以我用continue语句跳过i=2,从i=3处执行,这样就OK
        cout<<*films[i]<<endl;
    }

    cout<<"The winner is :"<<*pwin<<"!\n";
    cin.get();
    return 0;
}

结果:
这里写图片描述
auto_ptr 智能指针不能自动销毁new 出来的数字
eg

int main()
{
    using namespace std;
    double *pd=new double;
    *pd=1.222;
    unique_ptr<double> spd(pd);//ok

    double *pd1=new double[11]{9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,4.0};

    for(int i=0;i<9;i++)
    cout<<"pd1["<<i<<"] = "<<pd1[i]<<endl;
  //  delete[] pd1;
    return 0;
}

运行如下:
这里写图片描述
未delete[]pd1,堆内存未被回收
修改如下:

int main()
{
    using namespace std;
    double *pd=new double;
    *pd=1.222;
    unique_ptr<double> spd(pd);//ok

    double *pd1=new double[11]{9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,4.0};

    {
        unique_ptr<double[]> spd1(pd1);
    }

    for(int i=0;i<9;i++)
    cout<<"pd1["<<i<<"] = "<<pd1[i]<<endl;
  //  delete[] pd1;
    return 0;
}

运行:
这里写图片描述
可见,内存被销毁了!

最后说的是:
使用new 分配内存时,才能使用auto_ptr,shared_ptr,不是new分配的内存,不能使用,而使用new[],可以使用unique_ptr

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值