C++11 智能指针
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的指针所有权转义,可以通过使用swap
和std::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 智能指针相关推荐
- 详解C++11智能指针
详解C++11智能指针 前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用 ...
- 【C++11新特性】 C++11智能指针之weak_ptr
http://blog.csdn.net/xiejingfa/article/details/50772571 原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/ar ...
- c++11新特性_【C++11新特性】 C++11智能指针之weak_ptr
如题,我们今天要讲的是 C++11 引入的三种智能指针中的:weak_ptr. 在学习 weak_ptr 之前最好对 shared_ptr 有所了解.如果你还不知道 shared_ptr 是何物,可以 ...
- 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 原创)智能指针拾遗 (原创)智能指 ...
- C++11 智能指针时要避开的 10 大错误
我很喜欢C++11全新的智能指针,对于那些苦恼于自己管理内存的开发者来说,这是天大的好事.但是,在广泛使用C++11智能指针的两年里,因为使用方法不当而导致程序的效率下降甚至直接crash掉的事情发生 ...
- 使用 C++11 智能指针时要避开的 10 大错误
http://blog.jobbole.com/104666/ 我很喜欢新的C++11的智能指针.在很多时候,对很多讨厌自己管理内存的人来说是天赐的礼物.在我看来,C++11的智能指针能使得C++新手 ...
- 十大愚蠢的错误,以避免与C ++ 11智能指针
Top 10 dumb mistakes to avoid with C++ 11 smart pointers I love the new C++ 11 smart pointers. In ma ...
- c++11 智能指针 unique_ptr、shared_ptr与weak_ptr
C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer),定义在<memory>中. 可以对动态资源进行管理,保证任何情况下,已构 ...
- 窥见C++11智能指针
导语: C++指针的内存管理相信是大部分C++入门程序员的梦魇,受到Boost的启发,C++11标准推出了智能指针,让我们从指针的内存管理中释放出来,几乎消灭所有new和delete.既然智能指针如此 ...
- 【C++11新特性】 C++11智能指针之shared_ptr
http://blog.csdn.net/Xiejingfa/article/details/50750037 原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/ar ...
最新文章
- IBM之alphablox 数据源定义问题解决
- YOLOv3在OpenCV4.0.0/OpenCV3.4.2上的C++ demo实现
- 如何设计好词袋模型BoW模型的类类型
- 计算机频率、内存相关杂谈
- 大牛推荐的30本经典编程书籍,从Python到前端全系列。
- lsattr/chattr
- UIAlertAction添加输入框
- linux 查看文件工具,lsof---Linux查看文件信息的强大工具
- 在线开关MySQL5.7 GTID_MySQL5.7 GTID在线开启与关闭【转】
- 我的世界java版如何装mod_我的世界考古“初代贝爷生存”?开局3滴血,还没进游戏就要自闭了...
- 哈工大学习笔记 | 图文并茂详解隐马尔可夫模型
- 蒙特卡洛树搜索算法(UCT): 一个程序猿进化的故事
- 遇到一个奇怪的问题——关于VS2013、VS2015中字符集(多字节字符集和Unicode字符集)的选择
- python三维数据转换成二维_用Python生成马赛克画
- 无尽的生命 洛谷p2448
- 处理数据库镜像问题的一个案例——数据库主体与镜像断开连接
- 大事•Pandownload凉了
- 设置计算机访问权限密码忘了怎么办,苹果访问限制密码是什么?忘记怎么办【详解】...
- IDEA服务器端JQuery框架加载失败--已解决
- Hexo中添加音乐(列表)、视频的代码