C++11标准库中提供的智能指针主要有:std::auto_ptr, std::unique_ptr, std::shared_ptr

std::auto_ptr在C++11中已经标记为弃用,而在C++17中就完全移除了,不建议使用std::auto_ptr。

头文件:

#include <memory>
using namespace std;

现有如下测试类:

class Apple {
public:Apple() {id_ = 0;cout << "Apple()" << endl;}Apple(int id) {id_ = id;cout << "Apple(" << id_ << ")" << endl;}~Apple() {cout << "~Apple()" << endl;}void SetId(int id) {id_ = id;}int GetId() {return id_;}
private:int id_;
};

一、 std::auto_ptr

std::auto_ptr在C++11中虽然已经弃用,但还可以使用;但在C++17中就完全移除了。
std::auto_ptr在自身被销毁时释放相应的对象。

int main()
{{auto_ptr<Apple> apple1(new Apple(1));} // 超出apple1的作用域,apple1被销毁,其指针指向的对象被析构。return 0;
}

std::auto_ptr支持赋值构造和复制赋值,但右值会失去指针的所有权,如:

auto_ptr<Apple> apple0(new Apple(1));
auto_ptr<Apple> apple1 = apple0;apple0.id();  // 引发异常

上面的代码中,apple0赋值给了apple1,此时apple1拥有指针的所有权,而apple0中的指针就是NULL了。
所以说,std::auto_ptr虽然可以复制,但涉及到指针所有权的转义,所以std::auto_ptr不能用在标准容器(如std::vector等)中。

二、 std::unique_ptr

2.1 使用unique_ptr

std::unique_ptr和std::auto_ptr一样,也是在自身被销毁时释放相应的对象。std::unique_ptr被设计用来取代std::auto_ptr.
std::unique_ptr支持普通指针的*,->操作符,但不支持普通指针的++, --算术操作运算符。

std::unique_ptr**不**支持赋值构造和复制赋值;不支持使用=赋值语法将一个普通的指针当作初始值:

unique_ptr<Apple> apple = new Apple(2); // 错误
unique_ptr<Apple> apple(new Apple(2));  // 正确
int main()
{{unique_ptr<Apple> apple2(new Apple(2));unique_ptr<Apple> apple3 = apple2; // 编译失败} // 超出apple2的作用域,apple2被销毁,其指针指向的对象被析构。
}

2.2 make_unique

可以使用std::make_unique来构造unique_ptr:

std::unique_ptr<Apple> apple = std::make_unique<Apple>(1);

2.3 所有权

std::unique_ptr不必一定拥有对象,它可以是empty。例如它被默认构造函数创建出来时:

unique_ptr<Apple> apple;

也可以调用reset()或对它赋予nullptr,来让它不拥有对象。
此外,可以使用release方法来返回一个指向被管理对象的指针,并释放所有权。

2.4 检查是否拥有对象

可以调用empty()来检查unique_ptr是否拥有对象;而且unique_ptr重载了bool()操作符,也可以直接将其转为bool类型来判断。

unique_ptr<Apple> apple;
if(apple.empty()) {
}if(apple) {
}

2.5 所有权转义

虽然std::unique_ptr不支持支持赋值构造和复制赋值,但其要实现类似std::auto_ptr的指针所有权转义,可以通过使用swapstd::move来实现,因为std::unique_ptr实现了转移构造函数转移赋值操作符重载:

int main()
{{unique_ptr<Apple> apple2(new Apple(2));unique_ptr<Apple> apple3;apple2.swap(apple3);     // apple2的指针从此无效/*或者:unique_ptr<Apple> apple3 = std::move(apple2);  // apple2指针从此无效*/} // 超出apple2的作用域,apple2被销毁,其指针指向的对象被析构。
}

2.6 处理Array

默认情况下unique_ptr如果失去所有权(也许因为被销毁,或因为被赋予新值,或因为变成empty),会为其所拥有的对象调用delete。不幸的是C++无法区分指针是“指向单对象”还是“指向数组”。而C++语言又规定,对于数组应该使用delete[]而不是delete。所以下面的语句是错误的:

unique_ptr<Apple> apples(new Apple[10]);  // 错误

为了处理数组,C++标准库为unique_ptr提供了一个偏特化版本(partial specialization)来处理数组,在失去对象的所有权时,对该对象调用delete[]。

unique_ptr<Apple[]> apples(new Apple[10]);

但是,这个偏特化的版本不在提供操作符*,->的支持,改而提供操作符[]的支持,用来访问其所指向的数组中的某一个对象:

unique_ptr<Apple[]> apples(new Apple[10]);  // OK
apples[0].SetId(0);   // OK

2.7 自定义deleter

当所指向的对象要求不只是调用delete或delete[]来释放对象时,就需要指定自己的deleter。unique_ptr的deleter可以是类、函数指针。
如果deleter是类,则该类必须提供操作符()的重载,参数必须是指向对象的指针,如下:

class AppleDeleter {
public:void operator()(Apple* p) {std::cout << "will delete Apple object" << std::endl;p->SetId(0);delete p;}
};int main()
{std::unique_ptr<Apple, AppleDeleter> apple(new Apple(1));apple.reset();return 0;
}

如果deleter是函数指针,则函数指针为void(*)(T*)std::function<void(T*)>,如下:

void AppleDeleter(Apple* p) {std::cout << "will delete Apple object" << std::endl;p->SetId(0);delete p;
}int main()
{std::unique_ptr<Apple, void(*)(Apple*)> apple(new Apple(1), AppleDeleter);apple.reset();return 0;
}

可以使用typedef定义一个中介的类型定义式:

typedef void(*PFNAppleDeleter)(Apple*);void AppleDeleter(Apple* p) {std::cout << "will delete Apple object" << std::endl;p->SetId(0);delete p;
}int main()
{std::unique_ptr<Apple, PFNAppleDeleter> apple(new Apple(1), AppleDeleter);apple.reset();return 0;
}

三、 std::shared_ptr

3.1 使用shared_ptr

std::shared_ptr和boost中的shared_ptr类似,当对象的引用计数为0时,对象会被释放。
std::shared_ptr支持赋值构造和复制赋值,左值和右值同时有效,引用计数会加1。

int main()
{{shared_ptr<Apple> apple3(new Apple(3));{shared_ptr<Apple> apple4 = apple3;}} // 此时Apple对象才会析构。return 0;
}

你可以先声明shared_ptr,然后对它赋值一个指针。然而不可以直接使用=赋值操作符,必须改用reset()

std::shared_ptr<Apple> apple;
apple.reset(new Apple(1));

3.2 std::make_shared

可以使用std::make_shared构造shared_ptr:

auto sp = std::make_shared<Apple>(12);

3.3 处理Array

前面介绍的std::unique_ptr在处理数组时,可以使用偏特化的版本,但std::shared_ptr没有提供用于处理数组的偏特化的版本。所以shared_ptr要处理数组,必须自定义deleter.

std::shared_ptr的deleter的定义和std::unique_ptr一样,但在使用deleter时,std::shared_ptr不需要再模板参数中提供deleter定义,如:

void AppleDeleter(Apple* p) {std::cout << "will delete Apple object" << std::endl;delete []p;
}int main()
{// 模板参数只有一个std::shared_ptr<Apple> apples(new Apple[10], AppleDeleter);apples.reset();return 0;
}

C++11 智能指针相关推荐

  1. 详解C++11智能指针

    详解C++11智能指针 前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用 ...

  2. 【C++11新特性】 C++11智能指针之weak_ptr

    http://blog.csdn.net/xiejingfa/article/details/50772571 原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/ar ...

  3. c++11新特性_【C++11新特性】 C++11智能指针之weak_ptr

    如题,我们今天要讲的是 C++11 引入的三种智能指针中的:weak_ptr. 在学习 weak_ptr 之前最好对 shared_ptr 有所了解.如果你还不知道 shared_ptr 是何物,可以 ...

  4. C++11智能指针(unique_ptr、shared_ptr、weak_ptr)boost::scoped_ptr

    C++11智能指针(unique_ptr.shared_ptr.weak_ptr)_-码农小非-的专栏-CSDN博客_c++ shared_ptr weak_ptr 原创)智能指针拾遗 (原创)智能指 ...

  5. C++11 智能指针时要避开的 10 大错误

    我很喜欢C++11全新的智能指针,对于那些苦恼于自己管理内存的开发者来说,这是天大的好事.但是,在广泛使用C++11智能指针的两年里,因为使用方法不当而导致程序的效率下降甚至直接crash掉的事情发生 ...

  6. 使用 C++11 智能指针时要避开的 10 大错误

    http://blog.jobbole.com/104666/ 我很喜欢新的C++11的智能指针.在很多时候,对很多讨厌自己管理内存的人来说是天赐的礼物.在我看来,C++11的智能指针能使得C++新手 ...

  7. 十大愚蠢的错误,以避免与C ++ 11智能指针

    Top 10 dumb mistakes to avoid with C++ 11 smart pointers I love the new C++ 11 smart pointers. In ma ...

  8. c++11 智能指针 unique_ptr、shared_ptr与weak_ptr

    C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer),定义在<memory>中. 可以对动态资源进行管理,保证任何情况下,已构 ...

  9. 窥见C++11智能指针

    导语: C++指针的内存管理相信是大部分C++入门程序员的梦魇,受到Boost的启发,C++11标准推出了智能指针,让我们从指针的内存管理中释放出来,几乎消灭所有new和delete.既然智能指针如此 ...

  10. 【C++11新特性】 C++11智能指针之shared_ptr

    http://blog.csdn.net/Xiejingfa/article/details/50750037 原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/ar ...

最新文章

  1. IBM之alphablox 数据源定义问题解决
  2. YOLOv3在OpenCV4.0.0/OpenCV3.4.2上的C++ demo实现
  3. 如何设计好词袋模型BoW模型的类类型
  4. 计算机频率、内存相关杂谈
  5. 大牛推荐的30本经典编程书籍,从Python到前端全系列。
  6. lsattr/chattr
  7. UIAlertAction添加输入框
  8. linux 查看文件工具,lsof---Linux查看文件信息的强大工具
  9. 在线开关MySQL5.7 GTID_MySQL5.7 GTID在线开启与关闭【转】
  10. 我的世界java版如何装mod_我的世界考古“初代贝爷生存”?开局3滴血,还没进游戏就要自闭了...
  11. 哈工大学习笔记 | 图文并茂详解隐马尔可夫模型
  12. 蒙特卡洛树搜索算法(UCT): 一个程序猿进化的故事
  13. 遇到一个奇怪的问题——关于VS2013、VS2015中字符集(多字节字符集和Unicode字符集)的选择
  14. python三维数据转换成二维_用Python生成马赛克画
  15. 无尽的生命 洛谷p2448
  16. 处理数据库镜像问题的一个案例——数据库主体与镜像断开连接
  17. 大事•Pandownload凉了
  18. 设置计算机访问权限密码忘了怎么办,苹果访问限制密码是什么?忘记怎么办【详解】...
  19. IDEA服务器端JQuery框架加载失败--已解决
  20. Hexo中添加音乐(列表)、视频的代码

热门文章

  1. 读书笔记 PCG in Games 程序化内容生成2 基于搜索的方法
  2. 李雪:今目标与企业共同成长
  3. 程序员有意思的导航(持续更新)
  4. 汉诺塔问题个人讲解及部分实现(JAVA递归)
  5. 质量工具之故障树分析FTA(3) - FTA的数学基础
  6. 最新elasticsearch7(五、结合mybatis、springboot实例)
  7. Linux内核——实模式
  8. OD调试3--reverseMe
  9. C语言黄金分割法解一元函数,黄金分割法-机械优化设计方案-C语言程序.doc
  10. 火炬之光模型导出(Unity加载火炬之光的模型)