智能指针之unique_ptr简单实现-实现篇

1 序

1.1 智能指针

为了避免手动在堆中分配出的内存没有释放造成内存泄露的问题,C++11提供了智能指针。

智能指针将指针封装成一个栈对象。栈对象在生命周期结束自动销毁时会调用析构函数。智能指针基本上也是在析构函数中做文章,实现的堆上内存管理。

C++11推荐使用的智能指针有unique_ptrshared_ptrweak_ptr三种。

1.2 内容简介

本文为std::unique_ptr的实现篇,介绍实现一个UniquePtr类,实现与std::unique_ptr类似的功能。代码实现参考了std::unique_ptr的实现,当然仅仅是简单的实现,准确的说是实现了std::unique_ptr的一种特例。

实现UniquePtr的目的仅仅是为了更直观理解学习std::unique_ptr用法和其实现中的亮点,并不是为了替代或者在工程中使用。代码都是需要时间去修改稳定的。大家公认的轮子,特别STL的轮子,直接学习使用就行了,不要自己搞。

1.3 测试环境

  • 系统:Windows | 10 ;

  • 编译环境:CLion | 2020.1.1 ;

  • 编译工具:CMake | 3.16.5;

  • 编译器:MinGW GCC | 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) ;

默认情况下gcc编译器会自动优化临时对象构造新对象的行为。为了更好的了解对象的构造流程,需要在CMake中添加如下命令关闭该优化。

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-elide-constructors")

1.4 示例说明

为了便于查看UniquePtr所托管指针的申请和释放,示例使用下面的自定义Test类。

class Test {
   
public:
    explicit Test(int a = 0) : a_(a), str_(new char[32]) {
    // explicit禁用隐式类型转换
        sprintf(str_, "%d", a_);
        printf("Test[%p].[%s] constructor\n", this, str_);
    }

    ~Test() {
   
        printf("~Test[%p].[%s]\n", this, str_);
        delete[] str_;
    }
    // ...
public:
    int a_;
    char *str_;
};

2 std::unique_ptr自定义deleter

std::unique_ptr支持传入自定义deleter,在std::unique_ptr对象释放析构的时候调用会调用该deleter释放托管指针内存。在不传入deleter的情况下,默认的deleter使用delete释放托管指针内存。

当使用std::unique_ptr去托管new[]生成的指针时,需要使用delete[]去释放托管指针内存。此时,默认的deleter就不可用,需要传入自定义的deleter。有了自定义的deleterstd::unique_ptr甚至可以托管文件流、套接字(socket)等。

2.1 仿函数方式

托管new[]的自定义的deleter可以使用仿函数实现。实现一个仿函数,在其中调用delete[]

template<typename T>
struct array_deleter {
   
    void operator()(T *p) {
   
        delete[] p;
    }
};

然后,使用如下方式传入array_deleter

std::unique_ptr<Test, array_deleter<Test>> t1(new Test[10]);

t1析构的时候会自动调用array_deleter,释放托管指针内存。

2.2 匿名函数方式

托管new[]的自定义的deleter可以使用匿名(lambda)函数实现。实现一个匿名函数,在其中调用delete[]。为了让代码看起来简洁可以将匿名函数存储在一个lambda_deleter变量中。

auto lambda_deleter = [](Test *p) -> void {
   
    delete[] p;
};

然后,使用如下方式传入lambda_deleter

std::unique_ptr<Test, decltype(lambda_deleter)> t2(new Test[10], lambda_deleter);

t2析构的时候会自动调用lambda_deleter,释放托管指针内存。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值