现代C++4-自己动手,实现C++的智能指针

上一讲,我们描述了一个某种程度上可以当成智能指针用的类 shape_wrapper。使用那个智能指针,可以简化资源的管理,从根本上消除资源(包括内存)泄漏的可能性。这一讲我们就来进一步讲解,如何将 shape_wrapper 改造成一个完整的智能指针。你会看到,智能指针本质上并不神秘,其实就是 RAII 资源管理功能的自然展现而已。

在学完这一讲之后,你应该会对 C++ 的 unique_ptr 和 shared_ptr 的功能非常熟悉了。同时,如果你今后要创建类似的资源管理类,也不会是一件难事。

回顾

我们上一讲给出了下面这个类:

class shape_wrapper {

public:

explicit shape_wrapper(

shape* ptr = nullptr)

: ptr_(ptr) {}

~shape_wrapper()

{

delete ptr_;

}

shape* get() const { return ptr_; }

private:

shape* ptr_;

};

这个类可以完成智能指针的最基本的功能:对超出作用域的对象进行释放。但它缺了点东西:

这个类只适用于 shape 类

该类对象的行为不够像指针

拷贝该类对象会引发程序行为异常

下面我们来逐一看一下怎么弥补这些问题。

模板化和易用性

要让这个类能够包装任意类型的指针,我们需要把它变成一个类模板。这实际上相当容易:

template <typename T>

class smart_ptr {

public:

explicit smart_ptr(T* ptr = nullptr)

: ptr_(ptr) {}

~smart_ptr()

{

delete ptr_;

}

T* get() const { return ptr_; }

private:

T* ptr_;

};

和 shape_wrapper 比较一下,我们就是在开头增加模板声明 template <typename T>,然后把代码中的 shape 替换成模板参数 T 而已。这些修改非常简单自然吧?模板本质上并不是一个很复杂的概念。这个模板使用也很简单,把原来的 shape_wrapper 改成 smart_ptr<shape> 就行。

目前这个 smart_ptr 的行为还是和指针有点差异的:

它不能用 * 运算符解引用

它不能用 -> 运算符指向对象成员

它不能像指针一样用在布尔表达式里

不过,这些问题也相当容易解决,加几个成员函数就可以:

template <typename T>

class smart_ptr {

public:

…

T& operator*() const { return *ptr_; }

T* operator->() const { return ptr_; }

operator bool() const { return ptr_; }

}

拷贝构造和赋值

拷贝构造和赋值,我们暂且简称为拷贝,这是个比较复杂的问题了。关键还不是实现问题,而是我们该如何定义其行为。假设有下面的代码:

smart_ptr<shape> ptr1{create_shape(shape_type::circle)};

smart_ptr<shape> ptr2{ptr1};

对于第二行,究竟应当让编译时发生错误,还是可以有一个更合理的行为?我们来逐一检查一下各种可能性。

最简单的情况显然是禁止拷贝。我们可以使用下面的代码:

template <typename T>

class smart_ptr {

…

smart_ptr(const smart_ptr&)

= delete;

smart_ptr& operator=(const smart_ptr&)

= delete;

…

};

禁用这两个函数非常简单,但却解决了一种可能出错的情况。否则,smart_ptr<shape> ptr2{ptr1}; 在编译时不会出错,但在运行时却会有未定义行为——由于会对同一内存释放两次,通常情况下会导致程序崩溃。

我们是不是可以考虑在拷贝智能指针时把对象拷贝一份?不行,通常人们不会这么用,因为使用智能指针的目的就是要减少对象的拷贝啊。何况,虽然我们的指针类型是 shape,但实际指向的却应该是 circle 或 triangle 之类的对象。在 C++ 里没有像 Java 的 clone 方法这样的约定;一般而言,并没有通用的方法可以通过基类的指针来构造出一个子类的对象来。

我们要么试试在拷贝时转移指针的所有权?大致实现如下:

template <typename T>

class smart_ptr {

…

smart_ptr(smart_ptr& other)

{

ptr_ = other
  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员zhi路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值