C++智能指针
参考:https://www.cnblogs.com/wxquare/p/4759020.html
http://c.biancheng.net/view/7898.html
什么是智能指针
智能指针是指向动态分配的内存区(堆)里的对象。
智能指针有什么用
用于生存期控制,确保正确销毁动态分配的对象。防止内存泄漏。
理解智能指针需要从下面三个层次:
- 从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。
- 智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存。另外指针的释放时机也是非常有考究的,多次释放同一个指针会造成程序崩溃,这些都可以通过智能指针来解决。
- 智能指针还有一个作用是把值语义转换成引用语义。C++和Java有一处最大的区别在于语义不同,在Java里面下列代码:
你当然知道,这里其实只生成了一个对象,a和b仅仅是把持对象的引用而已。但在C++中不是这样,Animal a = new Animal(); Animal b = a;
Animal a; Animal b = a;
智能指针里面有什么,怎么设计实现的
利用自动调用的类的析构函数来释放内存。从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。
- 引用计数。
各个智能指针的异同
auto_ptr
已经在C++11里弃用,C++11开始起用如下3个智能指针。
shared_ptr
引用计数,指向相同内存。每析构一次,引用减一,直到为0,删除指向的堆内存。线程安全,读取需要加锁。
注意点
不能将指针直接赋值给一个智能指针。
避免循环引用。
不要用原始指针初始化多个
shared_ptr
。否则会多次释放同一块内存。
#include <iostream>
#include <memory>
int main() {
{
int a = 10;
std::shared_ptr<int> ptra = std::make_shared<int>(a);
//std::shared_ptr<int> ptra1 = std::make_shared<int>(a);//不要初始化多个,会出错。
std::shared_ptr<int> ptra2(ptra); //copy
std::cout << ptra.use_count() << std::endl;
int b = 20;
int *pb = &a;
//std::shared_ptr<int> ptrb = pb; //error
std::shared_ptr<int> ptrb = std::make_shared<int>(b);
ptra2 = ptrb; //assign
pb = ptrb.get(); //获取原始指针
std::cout << ptra.use_count() << std::endl;
std::cout << ptrb.use_count() << std::endl;
}
}
unique_ptr
和shared_ptr不一样,不能拷贝。只能移动。同一时间只能有一个unique_ptr指向一个对象。
#include <iostream>
#include <memory>
int main() {
{
std::unique_ptr<int> uptr(new int(10)); //绑定动态对象
//std::unique_ptr<int> uptr2 = uptr; //不能賦值
//std::unique_ptr<int> uptr2(uptr); //不能拷貝
std::unique_ptr<int> uptr2 = std::move(uptr); //轉換所有權
uptr2.release(); //释放所有权
}
//超過uptr的作用域,內存釋放
}
weak_ptr
weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator和->,*它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加**。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
使用的时候要检查是否为空。
如何使用
创建
std::shared_ptr<int> p1; //不传入任何实参
std::shared_ptr<int> p2(nullptr); //传入空指针 nullptr
std::shared_ptr<int> p3(new int(10));
std::shared_ptr<int> p3 = std::make_shared<int>(10);
//调用拷贝构造函数
std::shared_ptr<int> p4(p3);//或者 std::shared_ptr<int> p4 = p3;
//调用移动构造函数,因为move是非原子性的,比拷贝这个原子性的操作更快
std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);
智能指针带来了什么问题
问题
解决方案
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!