C++11 智能指针
来源:互联网 发布:淘宝需要生产许可证 编辑:程序博客网 时间:2024/06/16 15:51
C++11标准库中提供的智能指针主要有:std::auto_ptr, std::unique_ptr, std::shared_ptr。std::auto_ptr在C++11中已经标记为弃用,而在C++17中就完全移除了,不建议使用std::auto_ptr。
标准库提供的所有智能指针都在<memory>
头文件中。
#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]); // OKapples[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++:智能指针
- C++:智能指针
- 【C++】智能指针
- 【C++】智能指针
- C++PJ智能指针
- 【c++】智能指针
- 【C++】智能指针auto_ptr
- C++,智能指针
- C++,boost智能指针
- 智能指针模拟C
- [C++]智能指针
- 【C++】 浅析智能指针
- C++_智能指针
- C++:初识智能指针
- C++::智能指针
- 【C++】智能指针
- c智能指针:unique_ptr
- 【C++】智能指针
- 【Python】给列表添加删除元素的方法
- B-Tree 、B+树、B*树
- HBaseAdminDemo 使用客户端api-demo
- Math.Round()
- Python time 100 天以后的日期
- C++11 智能指针
- Jmeter中cookie自动存储
- CNN的经典结构
- 关于git中cherry-pick的使用,选择一部分提交的代码合并到另一个分支
- qualcomm camera 学习笔记
- python 几个重要函数
- EC20模块GPS功能的使用
- 高并发环境下生成订单唯一流水号方法:SnowFlake
- ios 温度计的实现