C++基础智能指针

目录

一、引入背景

二、智能指针 

三、unique_ptr(独占智能指针)

3.1 独占智能指针的概述

3.2 类的原型

3.3 初始化 

3.4 独占智能指针的注意事项

3.5 智能指针的更多技巧

四、shared_ptr(共享智能指针)

4.1 概述

 4.2 基本使用

4.3 更多细节

五、智能指针的删除器(了解)

六、weak_ptr(弱智能指针)

6.1 引入目的

6.2 weak_ptr是什么

6.3 如何使用weak_ptr

6.4 weak_ptr的使用


一、引入背景

        1> C++中在堆区申请空间和释放空间需要使用new和delete完成

        2> 多个指针指向同一个内存空间,释放其中一个的空间,另一个还在继续使用(悬空指针)

        3> 只是申请了内存空间,使用后忘记释放内存空间,堆区对象没有得到析构

        4> 栈取申请的对象空间,在脱离对象空间后,会自动调用析构函数完成资源的回收,但是堆区的不会自动释放

 

#include <iostream>
​
using namespace std;
class Test
{
private:
    string name;
public:
    Test() {cout<<"Test::无参构造"<<endl;}
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}
    ~Test() {cout<<name<<"::析构函数"<<endl;}
};
​
int main()
{
    Test *p = new Test("张飞");
​
    cout << "Hello World!" << endl;
    return 0;
}

 

        5> 总结:上述例子中,在堆区申请一个对象空间,但是没有手动释放空间,造成对象没有析构,为了保证堆区空间使用的安全性,我们引入了智能指针,目的是更加安全的使用堆区空间。

二、智能指针 

        1> C++11标准提供了两种智能指针,分别是unique_ptr(独占智能指针)、shared_ptr(共享智能指针)

        2> 除了上述两种指针外,还有auto_ptr(自动智能指针,已弃用)、weak_ptr(弱智能指针,辅助shared_ptr作用)

        3> 以上所有智能指针都在头文件:#include中

        4> 智能指针是类模板,在栈区创建智能指针对象

        5> 把普通指针交给智能指针管理

        6> 智能指针对象过期时,析构函数会自动释放智能指针管理的指针空间

三、unique_ptr(独占智能指针)

3.1 独占智能指针的概述

        独占智能指针会“拥有”它所指向的对象,某一时刻,只能有一个unique_ptr指向给定的对象,当该指针被销毁时,指向的对象也会随之释放。

3.2 类的原型

template <typename T, typename D = default_delete<T>>
class unique_ptr
{
public:
    explicit unique_ptr(pointer p) noexcept; // 不可用于转换函数。
    ~unique_ptr() noexcept;
    T& operator*() const;  // 重载*操作符。
    T* operator->() const noexcept; // 重载->操作符。
    unique_ptr(const unique_ptr &) = delete; // 禁用拷贝构造函数
    unique_ptr& operator=(const unique_ptr &) = delete; // 禁用赋值函数
    unique_ptr(unique_ptr &&) noexcept; // 右值引用。
    unique_ptr& operator=(unique_ptr &&) noexcept; // 右值引用
    
private:
    pointer ptr; // 内置的指针。
};

3.3 初始化 

方法一: unique_ptr<AA> p0(new AA("西施"));// 分配内存并初始化。

方法二: unique_ptr<AA> p0 = make_unique<AA>("西施"); // C++14标准。

方法三: AA* p = new AA("西施"); unique_ptr<AA> p0(p); // 用已存在的地址初始化。

1> 方法三

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
int main()
{
    Test *p1 = new Test("张三");          //在堆区申请空间
    unique_ptr<Test> up1(p1);            //使用原始指针实例化一个指针指针
​
    cout<<"name = "<<(*p1).name<<endl;        //指针找到对象使用
    cout<<"name = "<<p1->name<<endl;          //原始指针直接使用
    cout<<"name = "<<(*up1).name<<endl;       //智能指针访问
    cout<<"name = "<<up1->name<<endl;          //智能指针访问
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

2> 使用方式1:

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
int main()
{
​
    unique_ptr<Test> up1(new Test("张三"));            //使用原始指针实例化一个指针指针
​
​
    cout<<"name = "<<(*up1).name<<endl;       //智能指针访问
    cout<<"name = "<<up1->name<<endl;          //智能指针访问
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

 3> 使用方法2只有C++14标准后才能使用,C++11标准不支持

3.4 独占智能指针的注意事项

1> 重载的*和->运算符重载,所以可以跟像使用普通指针一样使用该智能指针

2> 不支持拷贝构造和拷贝赋值函数

3> 不要使用一个原始指针初始化多个unique_ptr

4> get()函数可以返回该智能指针的原始指针

5> 不要使用unique_ptr指向非new申请的空间

6> 有智能指针指向原始指针后,就不要再用原始指针手动释放了

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
int main()
{
    Test *p1 = new Test("张三");
​
    unique_ptr<Test> up1(p1);            //使用原始指针实例化一个指针指针
    unique_ptr<Test> up2(p1);           //使用一个原始指针实例化多个智能指针
​
​
​
    cout<<"name = "<<(*up1).name<<endl;       //智能指针访问
    cout<<"name = "<<up1->name<<endl;          //智能指针访问
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

7> 智能指针作为函数参数传递时,传递引用,不要传递值,因为智能指针没有拷贝构造函数

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
//void fun(unique_ptr<Test> up)        //定义时不会报错,但是使用时会报错
void fun(unique_ptr<Test> &up)
{
    
}
​
​
​
int main()
{
    Test *p1 = new Test("张三");
​
    unique_ptr<Test> up1(p1);            //使用原始指针实例化一个指针指针
​
​
    cout<<"name = "<<(*up1).name<<endl;       //智能指针访问
    cout<<"name = "<<up1->name<<endl;          //智能指针访问
    
    //调用函数传递智能指针的值
    fun(up1);                  //报错,会告诉没有拷贝构造函数
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

 8> 智能指针不支持:+、-、++、--

3.5 智能指针的更多技巧

        1> 将一个智能指针unique_ptr赋值给另一个指针时,可以赋值右值(移动构造存在),但是不能赋值左值(拷贝构造不存在)

        2> 使用nullptr给unique_ptr赋值时,会自动释放对象

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
​
​
​
int main()
{
    Test *p1 = new Test("张三");
​
    unique_ptr<Test> up1(p1);            //使用原始指针实例化一个指针指针
​
​
    cout<<"name = "<<(*up1).name<<endl;       //智能指针访问
    cout<<"name = "<<up1->name<<endl;          //智能指针访问
​
    up1 = nullptr;                     //用空指针给智能指针赋值时,会释放智能指针指向的对象
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

        3> 使用release()函数,可以释放unique_ptr的指针,并且将原指针返回

        4> std::move函数,可以转移原始指针的控制权,本质上调用的时移动构造函数

 

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
//函数1需要一个指针,但是不对这个指针负责
void fun1(const Test *p)
{
    cout<<"fun1::"<<p->name<<endl;
}
​
//函数2需要一个指针,并且对这个指针负责
void fun2(Test *p)
{
    cout<<"fun2::"<<p->name<<endl;
​
    delete p;
}
​
//函数3需要一个智能指针,但是不对这个指针负责
void fun3(unique_ptr<Test> &up)
{
    cout<<"fun3::"<<up->name<<endl;
}
​
//函数4需要一个智能指针,并对这个指针负责
void fun4(unique_ptr<Test> up)
{
    cout<<"fun3::"<<up->name<<endl;
}
​
​
​
​
int main()
{
​
    unique_ptr<Test> up1(new Test("张飞"));     //在堆区空间实例化一个对象,托管到智能指针
​
    cout<<"函数调用开始"<<endl;
//    fun1(up1.get());              //调用功能1函数,不会对指针负责
//    fun2(up1.release());          //调用功能2函数,会对指针负责
//    fun3(up1);                    //需要使用智能指针的引用,函数内不会对指针负责
    fun4(move(up1));              //使用一个智能指针,函数内对指针负责
​
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

5> reset()函数释放对象

函数原型:void reset(pointer __p = pointer())

使用方法: up->reset(); //释放up对象指向的资源

                up->reset(nullptr); //释放up对象指向的资源

                up->reset(new Test("夏侯")); //释放up对原对象的资源,并指向新对象 

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
int main()
{
​
    unique_ptr<Test> up1(new Test("张飞"));     //在堆区空间实例化一个对象,托管到智能指针
​
    cout<<"函数调用开始"<<endl;
​
    //up1.reset();
    up1.reset(new Test("夏侯"));          //释放原来对象的空间,指向新的空间
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

6> swap()函数交换两个unique_ptr的使用权

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
int main()
{
​
    unique_ptr<Test> up1(new Test("张飞"));     //在堆区空间实例化一个对象,托管到智能指针
    unique_ptr<Test> up2(new Test("夏侯"));
​
    cout<<"函数调用开始"<<endl;
​
    up1.swap(up2);           //调用两个指针的使用权
    cout<<"up1->name = "<<up1->name<<endl;     //夏侯
    cout<<"up2->name = "<<up2->name<<endl;     //张飞
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

7> unique_ptr也可以有原始指针的特性,当指向一个继承体系内的基类对象时,也有多态的特性,如同原始指针管理基类对象和派生类对象一样

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
​
    virtual void show()
    {
        cout<<"我是父类"<<endl;
    }
};
​
​
class Demo:public Test
{
public:
    void show() override
    {
        cout<<"我是子类"<<endl;
    }
};
​
​
int main()
{
​
    unique_ptr<Test> up1(new Demo);           //父类指针指向子类对象
​
    cout<<"函数调用开始"<<endl;
​
    up1->show();                 //调用子类中重写的父类的虚函数
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

 8> 智能指针也不是绝对安全的,当程序内有exit()退出程序时,全局智能指针会释放空间,但是局部智能指针不会

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
​
    virtual void show()
    {
        cout<<"我是父类"<<endl;
    }
};
​
​
​
​
int main()
{
​
    unique_ptr<Test> up1(new Test("张飞"));           //父类指针指向子类对象
​
    cout<<"函数调用开始"<<endl;
​
    exit(0);           //手动退出程序
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}
#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
​
    virtual void show()
    {
        cout<<"我是父类"<<endl;
    }
};
​
​
//全局定义智能指针
unique_ptr<Test> up1(new Test("张飞"));           //父类指针指向子类对象
​
int main()
{
​
​
​
    cout<<"函数调用开始"<<endl;
​
    exit(0);           //手动退出程序
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

 9> unique_ptr提供了支持数组的具体化版本数组版本的unique_ptr,重载了[]运算符,返回的是引用,可以作为左值使用

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
​
int main()
{
​
    //1、普通指针指向数组的使用
//    Test *p = new Test[2];
    Test *p = new Test[2]{string("张飞"), string("夏侯")};
//    p[0].name = "张飞";
//    p[1].name = "夏侯";
//    cout<<"p[0].name = "<<p[0].name<<"     p[1].name = "<<p[1].name<<endl;
//    delete [] p;
​
​
    //2、使用智能指针指向数组
    unique_ptr<Test[]> up(new Test[2]);      //类型后需要加一个空的中括号
    //unique_ptr<Test[]> up(new Test[2]{string("张飞"), string("夏侯")});
    up[0].name = "张飞";
    up[1].name = "夏侯";
    cout<<"up[0].name = "<<up[0].name<<"     up[1].name = "<<up[1].name<<endl;
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

四、shared_ptr(共享智能指针)

4.1 概述

         shared_ptr共享他指向的对象,多个共享指针可以指向(关联)相同的对象,在内部采用计数器机制来实现当新的shared_ptr与对象关联时,引用计数器增加1当shared_ptr超出作用域时,引用计数器减1,当引用计数器变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
​
int main()
{
    Test *p = new Test("张飞");          //使用原始指针指向一个对象
​
    shared_ptr<Test> sp1(p);          //构造一个共享智能指针
    cout<<"sp1.use_count = "<<sp1.use_count()<<endl;          //显式当前指针的引用计数器  1
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

 4.2 基本使用

        shared_ptr的构造函数也是explicit,但是没有删除拷贝构造函数和拷贝赋值函数

1> 初始化

方法一:
shared_ptr<AA> p0(new AA("西施"));// 分配内存并初始化。
方法二:
shared_ptr<AA> p0 = make_unique<AA>("西施"); // C++11标准,推荐使用,效率更高
方法三:
AA* p = new AA("西施");
shared_ptr<AA> p0(p); // 用已存在的地址初始化。
方法四:
shared_ptr<AA> p0(new AA("西施"));// 分配内存并初始化。
shared_ptr<AA> p1(p0);            //拷贝构造
shared_ptr<AA> p2 = p0;            //拷贝构造
#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
​
int main()
{
    Test *p = new Test("张飞");          //使用原始指针指向一个对象
​
    shared_ptr<Test> sp1(p);          //构造一个共享智能指针
    cout<<"sp1.use_count = "<<sp1.use_count()<<endl;          //显式当前指针的引用计数器  1
​
    shared_ptr<Test> sp2(sp1);        //拷贝构造
    shared_ptr<Test> sp3 = sp2;       //拷贝构造
    cout<<"sp1.use_count = "<<sp1.use_count()<<endl;          //显式当前指针的引用计数器  3
    cout<<"sp2.use_count = "<<sp2.use_count()<<endl;          //显式当前指针的引用计数器  3
    cout<<"sp3.use_count = "<<sp3.use_count()<<endl;          //显式当前指针的引用计数器  3
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

2> 使用方法

1、智能指针重载了*和->操作符,可以像使用原始指针一样使用shared_ptr

2、use_count()函数返回引用计数器的个数

3、unique()函数,如果use_count()为1,返回true,否则返回false

4、支持普通的拷贝和赋值,左值的shared_ptr的计数器减1,右值的shared_ptr的计数器将加1

left = right;

5、get()函数返回原始指针

6、不要用同一个原始指针区初始化多个shared_ptr

7、不要使用shared_ptr管理不是new分配的空间内存

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
​
int main()
{
    shared_ptr<Test> spa1(new Test("张飞"));          //构造一个共享智能指针
    shared_ptr<Test> spa2(spa1);        //拷贝构造
    shared_ptr<Test> spa3 = spa2;       //拷贝构造
    cout<<"spa1.use_count = "<<spa1.use_count()<<endl;          //张飞的指针个数  3
​
​
    shared_ptr<Test> spb1(new Test("夏侯"));      //构造夏侯的指针
    shared_ptr<Test> spb2(spb1);
    cout<<"spb1.use_count = "<<spb1.use_count()<<endl;             //夏侯的引用计数器  2
​
    spa2 = spb2;         //夏侯的引用计数器将加1,张飞的引用计数器减1
​
    cout<<"spa1.use_count = "<<spa1.use_count()<<endl;          //张飞的指针个数  2
    cout<<"spb1.use_count = "<<spb1.use_count()<<endl;             //夏侯的引用计数器  3
​
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

3> 用于函数参数

        跟unique_ptr一样

4> 不支持指针的运算:+、-、++、--

4.3 更多细节

1> 使用nullptr给shared_ptr赋值时,将计数器减1,如果计数器为0,释放对象资源,空的shared_ptr = nullptr;

2> str::move() 可以转移对原始指针的控制权,还可以将unique_ptr转变成shared_ptr

3> reset()改变与资源的关联关系

pp.reset(); //解除与资源的关系,资源的引用计数器减1

pp.reset(new AA("bbb")); //解除与资源的关系,引用计数器减1,关联新资源

4> swap()函数交换两个shared_ptr的控制权

5> shared_ptr也可以像普通指针那样,完成多态的性质,使用方式跟原始指针一致

6> shared_ptr不是绝对安全的,如果程序中调用了exit()退出,全局的shared_ptr会自动释放,局部的shared_ptr无法释放

7> shared_ptr提供的智能指针数组的具体化版本,重载了[],返回值是一个引用,可以作为左值使用

8> shared_ptr的线程安全性:

        shared_ptr的引用计数器是线程安全的(引用计数器是原子操作)

        多个线程同时读一个shared_ptr对象是线程安全的

        如果多个线程对同一个shared_ptr对象进行读和写,则需要加锁

        多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,都要加锁进行保护

9> 实际开发过程中,unique_ptr能解决的问题,尽量不要使用shared_ptr,因为unique_ptr效率更高,所用资源更少

五、智能指针的删除器(了解)

        在默认情况下,智能指针过期的时候,用 delete 原始指针;

        释放管理的资源程序员也可以自定义删除器,改变智能指针释放资源的行为

        删除器可以是全局函数、仿函数以及Lambda表达式,形参为原始指针

#include <iostream>
#include<memory>
​
using namespace std;
class Test
{
public:
    string name;          //名字
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
//全局函数作为删除器
void deletefunc(Test *p)
{
    cout<<"自定义删除器:全局函数实现"<<endl;
    delete  p;
}
​
//定义仿函数作为删除器
class deleteclass
{
public:
    void operator()(Test *p)
    {
        cout<<"仿函数实现删除器"<<endl;
        delete p;
    }
};
​
//定义lambda作为删除器
auto deleteLamb = [](Test *p){
    cout<<"lambda表达式作为删除器"<<endl;
    delete  p;
};
​
​
​
int main()
{
    //shared_ptr<Test> spa1(new Test("张飞"));          //使用默认的删除器
​
    /*shared_ptr<Test> spa1(new Test("张飞"),deletefunc);*/     //使用全局函数作为删除器
//    shared_ptr<Test> spa1(new Test("张飞"),deleteclass());         //使用仿函数作为删除器
//     shared_ptr<Test> spa1(new Test("张飞"),deleteLamb);
​
​
    //独占智能指针的删除器的使用
//    unique_ptr<Test, decltype (deletefunc)*> up1(new Test("夏侯"), deletefunc);   //全局函数作为删除器
    unique_ptr<Test, void (*)(Test *)> up1(new Test("夏侯"), deletefunc);          //使用函数指针推导
//    unique_ptr<Test, deleteclass> up1(new Test("夏侯"), deleteclass());            //仿函数作为删除器
//    unique_ptr<Test, decltype (deleteLamb)> up1(new Test("夏侯"), deleteLamb);      //lambda表达式作为删除器
​
​
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

六、weak_ptr(弱智能指针)

6.1 引入目的

        shared_ptr内部维护了一个共享的引用计数器,多个shared_ptr可以指向同一个资源如果出现了循环引用的情况,引用计数器将永远无法归0,资源不会被释放

#include <iostream>
#include<memory>
​
using namespace std;
class Demo;
​
​
class Test
{
public:
    string name;          //名字
    shared_ptr<Demo> sp;   //共享智能指针
​
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
class Demo
{
public:
    string name;          //名字
    shared_ptr<Test> sp;    //共享智能指针
​
    Demo() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Demo(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Demo() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
​
int main()
{
    shared_ptr<Test> sp1(new Test("张飞"));
    shared_ptr<Demo> sp2(new Demo("夏侯"));
​
    //将他们的彼此的共享指针成员指向彼此
    sp1->sp = sp2;
    sp2->sp = sp1;
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}

6.2 weak_ptr是什么

1> weak_ ptr 是为了配合shared_ ptr 而引入的,它指向一个由shared_ ptr 管理的资源但不影响资源的生命周期。也就是说,将-个weak_ ptr 绑定到一个shared_ ptr 不会改变shared_ ptr 的引用计数。

2> 不论是否有weak_ ptr 指向,如果最后一个指向资源的shared_ ptr 被销毁,资源就会被释放。

3> weak_ ptr更像是shared_ ptr 的助手而不是智能指针。

6.3 如何使用weak_ptr

1> weak_ptr没有重载->和*运算符,不能直接访问资源

2> operator=(); 把shared_ptr或weak_ptr赋值给weak_ptr

3> expired(); 判断它指向的资源释放已经过期

4> lock(); 返回shared_ptr,如果资源已经过期,返回空的shared_ptr

5> reset(); 将当前的weak_ptr置空

6> swap(); 交换

7> weak_ptr不控制对象的生命周期,但是,它知道对象是否还活着

        用lock()函数可用把它提升为shared_ptr,如果对象还活着,返回有效的shared_ptr,如果对象已经死了,提升会失败,返回一个空的shared_ptr 提升的行为(lock)是线程安全的

6.4 weak_ptr的使用

1> 单线程可用,多线程不安全版本

#include <iostream>
#include<memory>
​
using namespace std;
class Demo;
​
​
class Test
{
public:
    string name;          //名字
    weak_ptr<Demo> sp;   //弱智能指针
​
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
class Demo
{
public:
    string name;          //名字
    weak_ptr<Test> sp;    //弱智能指针
​
    Demo() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Demo(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Demo() {cout<<name<<"::析构函数"<<endl;
​
​
            }              //析构函数
};
​
​
​
int main()
{
    shared_ptr<Test> sp1 = make_shared<Test>("张飞");        //创建一个共享智能指针
​
    {
        shared_ptr<Demo> sp2 = make_shared<Demo>("夏侯");      //在局部空间创建一个新对象
​
        //两个类对象的弱指针成员指向对方
        sp1->sp = sp2;
        sp2->sp = sp1;
​
        if(sp1->sp.expired() == true)
        {
            cout<<"语句块内部:sp1->sp已经过期"<<endl;
        }else
        {
            cout<<"语句块内部:sp1->sp.lock()->name = "<<sp1->sp.lock()->name<<endl;
        }
    }
​
    if(sp1->sp.expired() == true)
    {
        cout<<"语句块外部:sp1->sp已经过期"<<endl;
    }else
    {
        cout<<"语句块外部:sp1->sp.lock()->name = "<<sp1->sp.lock()->name<<endl;
    }
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}
​

2> 多线程安全版本

#include <iostream>
#include<memory>
​
using namespace std;
class Demo;
​
​
class Test
{
public:
    string name;          //名字
    weak_ptr<Demo> sp;   //弱智能指针
​
    Test() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Test() {cout<<name<<"::析构函数"<<endl;}              //析构函数
};
​
​
class Demo
{
public:
    string name;          //名字
    weak_ptr<Test> sp;    //弱智能指针
​
    Demo() {cout<<name<<"::无参构造"<<endl;}            //无参构造
    Demo(string n):name(n) {cout<<name<<"::有参构造"<<endl;}  //有参构造
    ~Demo() {cout<<name<<"::析构函数"<<endl;
​
​
            }              //析构函数
};
​
​
​
int main()
{
    shared_ptr<Test> sp1 = make_shared<Test>("张飞");        //创建一个共享智能指针
​
    {
        shared_ptr<Demo> sp2 = make_shared<Demo>("夏侯");      //在局部空间创建一个新对象
​
        //两个类对象的弱指针成员指向对方
        sp1->sp = sp2;
        sp2->sp = sp1;
​
        //定义一个共享智能指针,接收提升后的weak_ptr
        shared_ptr<Demo> t = sp1->sp.lock();          //原子操作,线程安全
​
        if(t == nullptr)
        {
            cout<<"语句块内部:sp1->sp已经过期"<<endl;
        }else
        {
            cout<<"语句块内部:t->name = "<<t->name<<endl;
        }
    }
​
    //定义一个共享智能指针,接收提升后的weak_ptr
    shared_ptr<Demo> t = sp1->sp.lock();          //原子操作,线程安全
​
    if(t == nullptr)
    {
        cout<<"语句块外部:sp1->sp已经过期"<<endl;
    }else
    {
        cout<<"语句块外部:t->name = "<<t->name<<endl;
    }
​
​
    cout << "********程序到此结束!********" << endl;
    return 0;
}
​

  • 27
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值