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

来源:互联网 发布:算法视频教程 编辑:程序博客网 时间:2024/06/06 10:38

在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()更改,okunique_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 0
原创粉丝点击