• C++ STL Smart Pointer 智能指针(一)shared_ptr和weak_ptr


    C++标准库提供了两大类型的smart pointer

      一、class shared_ptr。共享式拥有。多个shared_ptr可以指向同一个对象,该对象和起相关资源会在最后一个指针被销毁时释放。

      二、class unique_ptr。独占式拥有。同一时间只有一个smart pointer可以指向该对象。对于避免资源泄露特别有用。

    1.Class shared_ptr

    1.1 使用shared_ptr

      可以像使用其他指针一样使用shared_ptr。可以赋值、拷贝、比较,也可以使用*和->操作符。

    #include <iostream>
    #include <string>
    #include <memory>
    #include <vector>
    
    using namespace std;
    
    int main(){
        shared_ptr<string> pNico(new string("nico"));
        shared_ptr<string> pJutta(new string("jutta"));
        cout<<*pNico<<endl;
        cout<<*pJutta<<endl;
        (*pNico)[0]='N';
        pJutta->replace(0,1,"J");
        cout<<*pNico<<endl;
        cout<<*pJutta<<endl;
        vector<shared_ptr<string>> whoMadeCoffee;
        whoMadeCoffee.push_back(pJutta);
        whoMadeCoffee.push_back(pJutta);
        whoMadeCoffee.push_back(pNico);
        whoMadeCoffee.push_back(pJutta);
        whoMadeCoffee.push_back(pNico);
        cout<<"vector whoMadeCoffee:"<<endl;
        for(auto ptr:whoMadeCoffee){
            cout<<*ptr<<" ";
        }
        cout<<endl;
        *pNico="Nicolai";
        cout<<"vector whoMadeCoffee:"<<endl;
        for(auto ptr:whoMadeCoffee){
            cout<<*ptr<<" ";
        }
        cout<<endl;
        cout<<"use_count:"<<whoMadeCoffee[0].use_count()<<endl;
        whoMadeCoffee.clear();
        cout<<"use_count:"<<whoMadeCoffee[0].use_count()<<endl;
        return 0;
    }

    输出:

    nico
    jutta
    Nico
    Jutta
    vector whoMadeCoffee:
    Jutta Jutta nico Jutta nico
    vector whoMadeCoffee:
    Jutta Jutta Nicolai Jutta Nicolai
    use_count:4
    use_count:1
    

    1.2 析构策略

      1 我们可以声明属于自己的deleter。

      2 对于Array 我们可以用delete[]

    #include <iostream>
    #include <string>
    #include <memory>
    #include <vector>
    
    using namespace std;
    
    int main(){
        //定义一个Deleter
        shared_ptr<string> pNico(new string("nico"),[](string* p){
            cout<<"delete "<<*p<<endl;
            delete p;
        });
        shared_ptr<string> pJutta(new string("jutta"));
        vector<shared_ptr<string>> whoMadeCoffee;
        whoMadeCoffee.push_back(pJutta);
        whoMadeCoffee.push_back(pJutta);
        whoMadeCoffee.push_back(pNico);
        whoMadeCoffee.push_back(pJutta);
        whoMadeCoffee.push_back(pNico);
    
        //delete all pNico
        pNico=nullptr;
        whoMadeCoffee.resize(2);
    
        cout<<"vector whoMadeCoffee:"<<endl;
        for(auto ptr:whoMadeCoffee){
            cout<<*ptr<<" ";
        }
        cout<<endl;
        //对付Array
        shared_ptr<int> p(new int[10],[](int* p){
            delete[] p;
        });
        shared_ptr<int> p2(new int[10],default_delete<int[]>());
    
        unique_ptr<int[]> p3(new int[10]);
        unique_ptr<int,void(*)(int*)> p4(new int[10],[](int* p){
            delete[] p;
        });
        return 0;
    }

      运行结果:

    delete nico
    vector whoMadeCoffee:
    jutta jutta

      3 其他析构策略

      你可以制定属于自己的析构策略。比如当最后一个ptr被析构时,删除文件,你可以:

    #include <string>
    #include <memory>
    #include <fstream>
    #include <cstdio>
    
    using namespace std;
    
    class FileDeleter
    {
    public:
        FileDeleter(const string& fn):filename(fn){
    
        }
        void operator ()(ofstream* fp){
            fp->close();                //close file
            remove(filename.c_str());   //delete file
            cout<<"remove file"<<endl;
        }
    private:
        string filename;
    };
    int main(){ shared_ptr<ofstream> fp(new ofstream("tmpfile.txt"),FileDeleter("tmpfile.txt")); fp->write("aaa ",4); fp->write("aaa ",4); fp=nullptr; }

      

    2.Class weak_ptr

       weak_ptr允许你“共享但不拥有”对象,这个class会建立起一个shared_pointer。一旦最末一个拥有该对象的shared pointer失去了拥有权,任何weak pointer 都会自动成空。因此除了default和copy构造函数之外,weak_ptr只提供“接受一个shared_ptr”的构造函数。

      你不能使用*和->访问weak_ptr所指的对象。而是必须另外建立一个shared pointer。

    person.h

    #include <iostream>
    #include <string>
    #include <vector>
    #include <memory>
    
    using namespace std;
    
    class Person : public enable_shared_from_this<Person>
    {
    public:
        Person(const string& n,shared_ptr<Person> m=nullptr,shared_ptr<Person> f=nullptr);
        ~Person();
        void setParentsAndTheirKids(shared_ptr<Person> m=nullptr,shared_ptr<Person> f=nullptr);
    
        string name;
        shared_ptr<Person> mother;
        shared_ptr<Person> father;
        vector<shared_ptr<Person>> kids;
    
    };
    shared_ptr<Person> initFamily(const string& name);

    person.cpp

    #include "person.h"
    
    Person::Person(const string& n,shared_ptr<Person> m,shared_ptr<Person> f):
        name(n),mother(m),father(f)
    {
    
    }
    Person::~Person(){
        cout<<"delete "<<name<<endl;
    }
    void Person::setParentsAndTheirKids(shared_ptr<Person> m, shared_ptr<Person> f){
        mother=m;
        father=f;
        if(m!=nullptr){
            m->kids.push_back(shared_from_this());
        }
        if(f!=nullptr){
            f->kids.push_back(shared_from_this());
        }
    }
    shared_ptr<Person> initFamily(const string& name){
        shared_ptr<Person> mom(new Person(name+"'s mom"));
        shared_ptr<Person> dad(new Person(name+"'s dad"));
        shared_ptr<Person> kid(new Person(name,mom,dad));
        mom->kids.push_back(kid);
        dad->kids.push_back(kid);
        return kid;
    }

    main.cpp


    int
    main(){ shared_ptr<Person> p=initFamily("nico"); cout<<"nico's family exists"<<endl; cout<<"- nico is shared "<<p.use_count()<<" times"<<endl; //使用weak_ptr时,必须请问改变被指对象的访问方式,在式子内加上lock() cout<<"- name of 1st kid of nico's mom: "<<p->mother->kids[0].lock()->name<<endl; p=initFamily("jim"); cout<<"jim's family exists"<<endl; }

    输出:

    nico's family exists
    - nico is shared 3 times
    - name of 1st kid of nico's mom: nico
    jim's family exists

    将person.h改为:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <memory>
    
    using namespace std;
    
    class Person : public enable_shared_from_this<Person>
    {
    public:
        Person(const string& n,shared_ptr<Person> m=nullptr,shared_ptr<Person> f=nullptr);
        ~Person();
        void setParentsAndTheirKids(shared_ptr<Person> m=nullptr,shared_ptr<Person> f=nullptr);
    
        string name;
        shared_ptr<Person> mother;
        shared_ptr<Person> father;
        vector<weak_ptr<Person>> kids;
    
    };
    shared_ptr<Person> initFamily(const string& name);

    使用weak_ptr时,我们必须改变一下被指对象的访问方式,必须在式子内加入lock()。

    这会导致新产生一个得自于kids容器内含之weak_ptr的shared_ptr。如果无法进行这样的改动,lock()会产生一个empty的shared_ptr。

    main.cpp改为

    int main(){
        shared_ptr<Person> p=initFamily("nico");
        cout<<"nico's family exists"<<endl;
        cout<<"- nico is shared "<<p.use_count()<<" times"<<endl;
        //使用weak_ptr时,必须请问改变被指对象的访问方式,在式子内加上lock()
        cout<<"- name of 1st kid of nico's mom: "<<p->mother->kids[0].lock()->name<<endl;
        p=initFamily("jim");
        cout<<"jim's family exists"<<endl;
        return 0;
    }

    输出:

    nico's family exists
    - nico is shared 1 times
    - name of 1st kid of nico's mom: nico
    delete nico
    delete nico's dad
    delete nico's mom
    jim's family exists
    delete jim
    delete jim's dad
    delete jim's mom

       weak_ptr是shared_ptr的帮手,用来共享对象但不拥有对象。使用use_count()返回的是对象被shared_ptr拥有的次数,至于weak_ptr对它的共享次数是不计的。而且weak_ptr可以为空。

      一般而言,shared_ptr并非线程安全的。因此为避免data race造成的不明确行为,当你在多个线程中以shared_pointer指向同一个对象,你必须使用诸如mutex或lock等技术。

  • 相关阅读:
    核心API的使用(给定一个字符串,统计每个字符出现的次数)
    将博客搬至CSDN
    [DEBUG] python写文件时print漏掉整行数据
    [DEBUG] pyinstaller打包-命令行报错 pyinstaller failed to execute script 脚本名
    [DEBUG] springboot结合freemaker和js实现页面跳转和传值-踩坑记录
    724. 寻找数组的中心索引
    1010. 总持续时间可被 60 整除的歌曲
    27.移除元素
    [tensorflow] 入门day1-数据整理与展示
    [tensorflow] 安装
  • 原文地址:https://www.cnblogs.com/xiaoaofengyue/p/12885544.html
Copyright © 2020-2023  润新知