C++智能指针

C++11智能指针:unique_ptr,shared_ptr,weak_ptr

1.unique_ptr

#include <iostream>
#include <memory>
#include <vector>

using namespace std;

class Perso
{
public:
    string m_name;
    Perso() { cout << "调用无参构造函数" << endl; }
    Perso(const string& name) : m_name(name) { cout << "调用有参构造函数" << endl; }
    //Perso(const string & name){ m_name = name; cout << "调用有参构造函数" << endl; }
    ~Perso() { cout << "调用析构函数" << endl; }
};

unique_ptr<Perso> func()
{
    unique_ptr<Perso>ptr(new Perso("测试"));
    return ptr;
}

/******func1()需要一个指针,但不对这个指针负责******/
void func1(const Perso* a)
{
    cout << a->m_name.c_str() << endl;
}

/******func2()需要一个指针,对这个指针负责******/
void func2(const Perso* a)
{
    cout << a->m_name.c_str() << endl;
    delete a;
}

/******func3()需要一个智能指针,但不对这个智能指针负责******/
void func3(const unique_ptr<Perso>& a)
{
    cout << a->m_name.c_str() << endl;
}

/******func4()需要一个智能指针,对这个智能指针负责******/
void func4(const unique_ptr<Perso> a)
{
    cout << a->m_name.c_str() << endl;
}

int main()
{
    //第一种智能指针定义方法(不推荐)
    Perso* p = new Perso("李白");
    unique_ptr<Perso> ptr1(p);
    //unique_ptr<Perso> ptr1 = p;            错误,不能把普通指针直接赋值给智能指针
    //unique_ptr<Perso> ptr = ptr1;            错误,不能用于其他unique_ptr拷贝构造 
    //unique_ptr<Perso> ptr; ptr = ptr1;    错误,不能用=对unique_ptr进行赋值
    
    //p,ptr1, ptr1.get()指向的是同一块地址
    //get()方法返回裸指针
    cout << "裸指针的值:" << p                        << endl;
    cout << "ptr1输出的结果:" << ptr1                << endl;
    cout << "ptr1.get()输出的结果:" << ptr1.get()    << endl;
    cout << "ptr1的地址" << &ptr1                    << endl;
    cout << "m_name= " << ptr1->m_name                << endl;
    
    //第二种智能指针定义方法
    unique_ptr<Perso> ptr2(new Perso("白居易"));

    //第三种智能指针定义方法(C++14标准)
    unique_ptr<Perso> ptr3 = make_unique<Perso>("杜甫");

    //传参
    //①传引用(不能传值,unique_ptr 没有拷贝构造函数)
    //②不能用同一个裸指针初始化多个 unique_ptr

    //智能指针重载了 * 和 -> 操作符,可以像使用指针一样使用 unique_ptr
    //智能指针不支持指针的运算(+,-,++,--)

    unique_ptr<Perso[]> array1(new Perso[2]);    //unique_ptr数组
    unique_ptr<Perso[]> array2(new Perso[2]{ string("李商隐"),string("孟浩然") });

    unique_ptr<Perso> ptr1(new Perso("智能"));
    unique_ptr<Perso> ptr2;
    ptr2= unique_ptr<Perso>(new Perso("指针"));
    ptr2 = func();//先析构指针对象,再构造测试

    unique_ptr<Perso> pu(new Perso("王勃"));
    cout << "开始调用" << endl;
    func1(pu.get());        //func1()需要一个指针,但不对这个指针负责
    func2(pu.release());    //func2()需要一个指针,对这个指针负责
    func3(pu);                //func3()需要一个智能指针,但不对这个智能指针负责
    func4(move(pu));        //func4()需要一个智能指针,对这个智能指针负责
    cout << "调用完成" << endl;
}

/*
更多技巧:
1.将一个unqiue_ptr赋给另一个时,如果源unqiue_ptr是一个临时右值,编译器允许这样做,如果源unqiue_ptr
将存在一段时间,编译器将禁止这样做,一般用于函数返回值
2.用nullptr给unqiue_ptr赋值将释放对象,空的nullptr==unqiue_ptr
3.release()释放对原始指针的控制权,将unqiue_ptr置为空,返回裸指针(可用于把unqiue_ptr传递给子函数,
子函数将负责释放对象)
4.std::move()可以转移对原始指针的控制权
5.不要用 unqiue_ptr 管理不是 new 分配的内存
6.unqiue_ptr 也可像普通指针一样,当指向一个类继承体系的基类对象时,也具有多态性质,
如同使用裸指针管理基类对象和派生类对象那样
7.如果程序中调用exit()退出,全局的 unique_ptr 可以自动释放,但局部的 unique_ptr 无法自动释放
*/

2.shared_ptr

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

#include <iostream>
#include <memory>

using namespace std;

class Perso
{
public:
    string m_name;
    Perso() { cout << "调用无参构造函数" << endl; }
    Perso(const string& name) : m_name(name) { cout << "调用有参构造函数" << endl; }
    //Perso(const string & name){ m_name = name; cout << "调用有参构造函数" << endl; }
    ~Perso() { cout << "调用析构函数" << endl; }
};

int main()
{
    Perso* p = new Perso("李白");
    shared_ptr<Perso> ptr1(p);                                  //用已存在的地址进行初始化
    shared_ptr<Perso> ptr2(new Perso("杜甫"));                  //分配内存并进行初始化
    shared_ptr<Perso> ptr3 = make_shared<Perso>("白居易");      //C++11标准
    shared_ptr<Perso> ptr4 = ptr1;
   
    cout << "ptr1.use_cout()= " << ptr1.use_count() << endl;
    cout << ptr1->m_name << endl;
    cout << "ptr4.use_cout()= " << ptr4.use_count() << endl;
    cout << ptr4->m_name << endl;

    shared_ptr<Perso[]> array1(new Perso[2]);
    shared_ptr<Perso[]> array2(new Perso[2]{ string("李清照"),string("李贺")});

    return 0;
}

/*
1.use_cout()方法返回引用计数器的值
2.unique()方法,如果 use_cout()为1,返回true, 否则返回false
3.share_ptr 支持赋值,左值的 share_ptr 的计数器将减1,右值 share_ptr的计数器将加1
4.get()方法返回值裸指针
5.不要用同一个裸指针初始化多个 shared_ptr
6.不要用 shared_ptr 管理不是 new 分配的内存
7.用 nullptr 给 shared_ptr 赋值将把计数减1,如果计数为0,将释放对象,空的 shared_ptr==nullptr 
8.std::move()可以转移对原始指针的控制权,还可以将 unique_ptr 转移成 shared_ptr
9.reset()改变与资源的关联关系
    p.reset();  //解除与资源的关系,资源的引用计数减1
    p.reset(new Perso("赋值"));   //解除与资源的关系,资源的引用计数减1,关联新资源
10.shared_ptr 也可像普通指针一样,当指向一个类继承体系的基类对象时,也具有多态性质,
如同使用裸指针管理基类对象和派生类对象那样
11.如果程序中调用exit()退出,全局的 shared_ptr 可以自动释放,但局部的 shared_ptr 无法自动释放
12.shared_ptr的引用计数本身是线程安全(引用计数是原子操作)
   多个线程同时读写一个 shared_ptr 对象是线程安全的
   如果是多个线程对同一个 shared_ptr 对象进行读和写,则需要加锁
   多线程读写 shared_ptr 所指向的同一个对象,不管是相同的 shared_ptr 对象,还是不同的 shared_ptr 对象,也需要加锁保护
13.如果 unique_ptr 能解决问题,就不要用 shared_ptr,unique_ptr 的效率更高,占用的资源更少
*/

3.weak_ptr

/*
weak_ptr 是为了配合 shared_ptr 而引入的,它指向一个由 shared_ptr 管理的资源但不影响资源的生命周期
也就是说,将一个 weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用计数
不论是否有 weak_ptr 指向,如果最后一个指向资源的 shared_ptr 被销毁,资源就会释放
weak_ptr 更像是 shared_ptr 的助手而不是智能指针
*/

#include <iostream>
#include <memory>

using namespace std;

class Animal;

class Perso
{
public:
    string m_name;
    Perso() { cout << "调用无参构造函数Perso" << endl; }
    Perso(const string& name) : m_name(name) { cout << "调用有参构造函数Perso" << m_name .c_str() << endl; }
    //Perso(const string & name){ m_name = name; cout << "调用有参构造函数Perso" << endl; }
    ~Perso() { cout << "调用析构函数Perso" << m_name.c_str() << endl; }
    weak_ptr<Animal>m_p;
};

class Animal
{
public:
    string m_name;
    Animal() { cout << "调用无参构造函数Animal" << endl; }
    Animal(const string& name) : m_name(name) { cout << "调用有参构造函数Animal" << m_name.c_str() << endl; }
    //Animal(const string & name){ m_name = name; cout << "调用有参构造函数" << endl; }
    ~Animal() { cout << "调用析构函数Animal" << m_name.c_str() << endl; }
    weak_ptr<Perso>m_p;
};

int main()
{
    shared_ptr<Perso> ptr1 = make_shared<Perso>("李白");

    {
        shared_ptr<Animal> ptr2 = make_shared<Animal>("老虎");

        cout << "ptr1 的引用计数:" << ptr1.use_count() << endl;
        cout << "ptr2 的引用计数:" << ptr2.use_count() << endl;

        ptr1->m_p = ptr2;
        ptr2->m_p = ptr1;

        if (ptr1->m_p.expired() == true)
            cout << "语句块内部:ptr1>m_p已过期" << endl;
        else
            cout << "语句块内部:ptr1->m_p.lock()->m_nam " << ptr1->m_p.lock()->m_name << endl;
    }
    
    if (ptr1->m_p.expired() == true)
        cout << "语句块内部:ptr1>m_p已过期" << endl;

    else
        cout << "语句块内部:ptr1->m_p.lock()->m_nam " << ptr1->m_p.lock()->m_name << endl;

    return 0;
}

/*
1.weak_ptr 乜有重载 * 和 -> 操作符,不能直接访问资源
2.operator=() 把 weak_ptr 或者 shared_ptr 类型指针赋值给 weak_ptr。
3.expired()      判断当前 weak_ptr 指针为否过期(指针为空,或者指向的堆内存已经被释放)。
4.lock()      返回一个和当前 weak_ptr 指向相同的 shared_ptr 指针,如果 weak_ptr 已经过期,则返回空的 shared_ptr 指针;
5.reset()      将当前 weak_ptr 指针置为空指针。
6.swap()      交换

weak_ptr 不控制对象的生命周期,但是它知道对象是否还活着 
用 lock() 函数可以把它提升为 shared_ptr ,如果对象还活着,返回有效的 shared_ptr,如果对象死了,返回空的 shared_ptr
lock() 行为是线程安全的
*/

4.指针删除器

/*
在默认情况下,智能指针过期的时候,用 delete 原始指针,释放它管理的资源
可以自定义删除器,改变智能指针释放资源的行为
删除器可以是全局函数、仿函数和 lambada 表达式,形参为原始指针
*/

#include <iostream>
#include <memory>

using namespace std;

class Perso
{
public:
    string m_name;
    Perso() { cout << "调用无参构造函数" << endl; }
    Perso(const string& name) : m_name(name) { cout << "调用有参构造函数" << endl; }
    //Perso(const string & name){ m_name = name; cout << "调用有参构造函数" << endl; }
    ~Perso() { cout << "调用析构函数" << endl; }
};

/********删除器,普通函数*********/
void deletefunc(Perso *tmp)
{
    cout << "自定义删除器(全局函数)。" << endl;
    delete tmp;
}

/********删除器,仿函数*********/
struct deleteclass
{
    void operator()(Perso* tmp)
    {
        cout << "自定义删除器(仿函数)。" << endl;
        delete tmp;
    }
};

/********删除器,lambada表达式*********/
auto deletelamb = [](Perso* tmp)
{
    cout << "自定义删除器(lambada表达式)。" << endl;
    delete tmp;
};

int main()
{
    shared_ptr<Perso> ptr1(new Perso("李白"));    //用缺省的删除器

    unique_ptr<Perso, void(*)(Perso*)>ptr(new Perso("李白"), deletefunc);
    unique_ptr<Perso, decltype(deletefunc)*> ptr2(new Perso("李白"), deletefunc);
    unique_ptr<Perso, deleteclass> ptr3(new Perso("李白"), deleteclass());
    unique_ptr<Perso, decltype(deletelamb)> ptr4(new Perso("李白"), deletelamb);
    
    shared_ptr<Perso> ptr5(new Perso("李白"),deletefunc);
    shared_ptr<Perso> ptr6(new Perso("李白"), deleteclass());
    shared_ptr<Perso> ptr7(new Perso("李白"), deletelamb);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值