《白话C++》第10章 STL和boost,Page88 std::shared_ptr常用功能02

本文详细解释了std::shared_ptr在C++中的管理功能,如reset操作的注意事项,unique()和use_count()的用途,以及如何处理基类和派生类的智能指针转换。特别介绍了类系指针转换时的动态_cast和库提供的标准转换模板.
摘要由CSDN通过智能技术生成

(1)reset操作

std::shared_ptr的reset函数并不一定将裸指针释放,一样需要先判断引用计数是否归零。不过和其他智能指针一样,reset()函数可以带一个新的裸指针作入参。

(2)管理辅助

unique()判断一个shared_ptr当前是否在和别的对象共享裸指针。返回真代表这个指针独立拥有裸指针。

use_count()则返回共享引用的个数。这两个函数通常不会用于实际业务,仅作为程序员写程序时做一些简单的观察及测试。

(3)管理多态指针

面向对象设计中,经常出现声明为基类的指针,实际指向派生类。shared_ptr可以良好地处理这种情况。

下例演示一个基类B,有两个派生类D1和D2。

基类作为一个接口,它拥有纯虚函数,特别是它拥有一个“虚析构”。后者是shared_ptr将来可以正确删除指针,释放内存的重要保障。

struct B
{
    virtual void prn() = 0; ///纯虚函数
    //虚析构,shared_ptr将来可以正确删除指针,释放内存的中药保障
    virtual ~B(){} 
};

struct D1 : public B
{
    void prn() override {cout << 1 << endl;}
    ~D1() override {cout << "~D1" << endl;}
};

struct D2 : public B
{
    void prn() override {cout << 2 << endl;}
    ~D2() override {cout << "~D2" << endl;}
};

然后我们声明两个管理基类指针的shared_ptr变量。请注意二者的声明类型(也称静态类型)都是“shared_ptr <B>”,但实际创建的分别是派生类D2和D2:

void test()
{
    std::shared_ptr <B> sb1(new D1);
    std::shared_ptr <B> sb2(new D2);

    sb1->prn();
    sb2->prn();
}

调用test()函数,观察sb1和sb2,二者和裸指针一样,完美支持面向对象的多态特性,最终释放所调用的析构函数,也完全正确。

(4)类系指针转换

在类系中使用裸指针,可通过dynamic_cast<T>()或static_cast<T>()在基类和派生类指针减做转换。继续上例中的B、D1、D2三者:

B* pb = new D1;
D1* pd = dynamic_cast <D1*>(pb);

既然pb 实际上是指向一个D1类对象,所以通过dynamic_cast转换,可以将pb向下转换为“D1*”。甚至可以尝试将pb向下转换到“D2*”,当然这样只会得到一个nullptr,但代码合法:

if(D2* pd2 = dynamic_cast <D2*>(pb))
{
    ///这里的代码永远不会执行,因为pd2必为nullptr
    cout << "--------" << endl;
}

dynamic_cast、static_cast、const_cast等无法直接作用到智能指针身上:

std::shared_ptr <B> pb(new D1);

typedef std::shared_ptr <D1> D1Ptr;
D1Ptr pd (dynamic_cast <D1Ptr> (pb));

//以下这样更不行
D1Ptr pd2 (dynamic_cast <D1*> (pb));

编译失败,因为在编译看来,shared_ptr<B> 和 shared_ptr <D1>没有任何关系。这很合清理,尽管B和D1是基类和派生类的关系,但将二者套入shared_ptr<T>之后,不能说shared_ptr<B>和shared_ptr<D1>也有派生关系。

怎么解决呢?通过只能指针的get()成员得到裸指针自然就可以继续使用dynamic_cast/const_cast/static_cast等,但这样做很危险,很容易发生前面所说的“不作不会死”的情况。

为此C++11在库中提供了标准实现,又是三个很丑的转换操作模版:

template <class T, class U>
std::shared_ptr <T>
static_pointer_cast(const std::shared_ptr <U>& r);

template <class T, class U>
std::shared_ptr <T>
dynamic_pointer_cast(const std::shared_ptr <U>& r);

template <class T, class U>
std::shared_ptr <T>
const_pointer_cast(const std::shared_ptr <U>& r);

名字中间都插入了“pointer”,不过其实只用于处理shared_ptr类型,作用和各自去除pointer的转换操作类似:“static”版和“dynamic”版都可用于基类和派生类指针之间的双向转换,前者不作正确性检查,后者会在运行时尝试检查。“const”则用于处理常量和非常量指针(指智能指针所拥有的裸指针)之间的强制转换。

使用示例:

std::shared_ptr <B> pb(new D1);

std::shared_ptr <D1> pd(dynamic_pointer_cast <D1> (pb));
pd->prn();

注意,套入XXX_point_cast<T>中的类型,并不是shared_ptr<D1>,而只是D1。至于为什么不是“D1 *”,因为名称中的“point”已经说明所要转换的必须是指针,没必要再添加多余的“*”符号了。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值