C++ std::unique_ptr 总结

1. 开篇

今年定了 5 篇技术文章的指标, 为了不打脸, 国庆期间抓紧写一篇, 先从简单的基础开始.

2. 背景

对于 C++ 的程序员来说, 标准库提供的 unique_ptr 应该不陌生, 但很多时候其实是没有一个清晰的使用原则, 比如什么时候该用, 用了会有什么限制, 有什么收益, 似乎就是用了也就是用了, 不用也没什么.

本文尝试从几个不同的场景出发总结一下 unique_ptr 的一些特性和使用的收益和约束, 如果有理解不到位的地方欢迎各位大佬加以指正.

3. unique_ptr 介绍

unique_ptr 是 C++ 标准库提供的一种智能指针的实现, 拥有和管理一个对象

3.1 std::make_unique

make_unique 是用来构造一个 unique_ptr 对象的方法, 但需要在 C++14 之后才能使用
为什么 c11 没有这个? 据说是大佬们忘记加了

// 头文件增加 include
#include <memory> 
...
// 通过 make_unique 构造
std::unique_ptr<Test> u_p1 = std::make_unique<Test>(); 

// 通过 get 返回管理资源的裸指针
Test* p1 = u_p1.get();  

3.2 释放资源

当 unique_ptr 销毁或者调用 reset 的时候会调用删除器去尝试清理资源

{
  // 自动释放资源
  std::unique_ptr<Test> u_p1 = std::make_unique<Test>();
}

// 通过 reset 释放资源
std::unique_ptr<Test> u_p2 = std::make_unique<Test>();
u_p2.reset();

// release 释放了所有权, 但没有删除资源, 需要手动删除, 
std::unique_ptr<Test> u_p3 = std::make_unique<Test>();
Test* p3 = u_p3.release();  
delete p3;

3.3 移交所有权

unique_ptr 可以进行 move 操作, move 操作会移交管理资源的所有权

// 通过 move 操作, 移交所有权, 移交后, u_p1 不再管理资源
std::unique_ptr<Test> u_p1;
std::unique_ptr<Test> u_p2 = std::move(u_p1);

3.4 copy 操作不合法

unique_ptr 不可以进行 copy 操作, copy 操作会破坏管理资源的所有权唯一性

std::unique_ptr<Test> u_p1;
std::unique_ptr<Test> u_p2 = u_p1; // 不合法

4. unique_ptr 的使用

我们先假设存在测试类

// Heart
class Heart {};

4.1 做为成员变量

// Human
class Human {
...
 private:
  // 作为类的成员变量声明
  const std::unique_ptr<Heart> heart_; 
};

4.1.1 使用限制

当在头文件里使用 unique_ptr 后, 对于 Heart 这个类, 我们不能使用前置声明的方式, 例如:

// Heart
class Heart;

// Human
class Human {
...
 private:
  // 如果不指定删除器, 编译器会报错
  std::unique_ptr<Heart> heart_; 
};

unique_ptr 是模板类, 默认的删除器需要通过 sizeof 获取泛型数据类型的字节大小.
为了减少麻烦, 如果有比较多的习惯使用 unique_ptr, 那么就减少前置声明的使用

当然有的同学会说, 可以通过自定义删除器绕开一些问题, 但大多数工程使用自定义删除器是很少的个例, 不必要为了个例而且否定一个对于大多数场景是有利的原则.

4.1.2 对比裸指针

一个类声明的成员变量是 unique_ptr 还是裸指针? 理论上都是可以实现的, 但对于一个大型 C++ 工程而言, 这其实是一个影响程序可读性, 可维护性的问题.

先以 Human 这个例子来说, 当创造一个 Human 对象的时候, heart_ 就应该被构造出来了, 因为 heart_ 是 const 类型, 只能在构造函数内的初始化列表中构造, 那么如果有其他的地方需要使用这个 heart_ 所管理的资源, 前提就必须是在这个 Human 对象没有被释放之前.

这很好的声明了内存模型, 程序内部的资源管理关系也能体现出来, 对于读代码的人来说在同等认知情况下就非常容易理解原作者的意图.

我们试想一下, 假如以裸指针的方式声明, 在不去看逻辑是如何实现的前提下, 是不会明白原作者的意图的, 这就降低了程序的可读性和维护性.

4.2 做为函数参数

作为函数的参数, 说明当前的参数已经把所有权移交给当前的函数栈, 如果函数内部不使用持有这个资源, 当退出函数体后, 这个资源就会被释放掉.

这通常是一种移交所有权的方式

  void Human::test(std::unique_ptr<Heart> heart) {
    // Human 类声明了 类型为 unique_ptr 的变量 heart_
    heart_ = std::move(heart); 
  }

4.3 作为函数返回值

函数返回 unique_ptr 说明这个方法是一个用来构造资源的工厂方法, 只负责构造资源, 但不持有所有权.

// HeartFactory
class HeartFactory {
  std::unique_ptr<Heart> CreateHeart() {
    return std::make_unique<Heart>();
  }
};

4.3.1 对比裸指针

返回值如果是裸指针, 说明函数只是把管理的资源提供给外部使用, 但资源的所有权还在调用的这个对象内部.

5. 总结

可以看到 unique_ptr 使用并不复杂, 但恰当的使用可以使得程序的内存模型结构非常的清晰, 所有权明确, 对于读代码的人来说很好的降低理解成本, 提高可维护性.

可运行的程序是程序员的最低目标, 一个好的程序员应该追求提高可读性, 可维护性

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容