[学习笔记]智能指针
介绍
- 会自动delete(不会导致内存泄漏)
- 智能指针是class
- c++11智能指针均在库memory中
基本操作
std::auto_ptr
c++11中被彻底放弃,被std::unique_ptr取代
- 初始化
auto_ptr<T> ptr(new T(value));
auto_ptr<T> ptr;
ptr.reset(new T(value));
- 访问方式
ptr->ClassFunciton();
ptr.get()->ClassVariable;
(*ptr).ClassVariable;
- 判断智能指针是否为空
if(ptr.get()==NULL)
- 存在潜在的内存崩溃问题:赋值 or 复制后原指针为NULL(悬空),不能再使用
- 赋值:a=b——最好不使用赋值操作符=
- auto_ptr管理的对象不能放入vector等stl容器
- auto_ptr最好不要当成参数传递
- 复制:auto_ptr
ptr1(ptr2);
- 赋值:a=b——最好不使用赋值操作符=
- 释放指针
T* tmp = ptr.release(); delete tmp; //release()函数只是让出内存所有权
ptr.reset();
std::unique_ptr
能达到boost::scoped_ptr的效果
- 初始化
unique_ptr<T> ptr(new T(value));
unique_ptr<T> ptr;
ptr.reset(new T(value));
//better (c++14)
unique_ptr<T> ptr=make_unique<T>(value);
- 判断智能指针是否为空
if(ptr.get()==nullptr)
- 禁止复制语义,即独享所有权:复制和赋值都被标记为delete
- 特例:可以通过函数返回一个unique_ptr
- 转移堆内存:移动构造 std::move
unique_ptr<T> ptr2(move(ptr1));
unique_ptr<T> ptr3=move(ptr1);
array
- 初始化
unique_ptr<T[]> ptr(new T[N]);
unique_ptr<T[]> ptr;
ptr.reset(new T[N]);
unique_ptr<T[]> ptr(make_unique<T[]>(N));
std::shared_ptr
- 用于共享所有权:在内部使用了引用计数:ptr.use_count()
- 一旦ptr.use_count()计数器变为0, 就会自动释放自己所管理的对象
- 初始化
shared_ptr<T> ptr(new T(value));
shared_ptr<T> ptr;
ptr.reset(new T(value));
//better (c++14)
shared_ptr<T> ptr=make_shared<T>(value);
- 可以复制、赋值
- 释放指针
T* tmp = ptr.release(); //use_count()会-1
std::enable_shared_from_this
在类中返回包含当前对象的一个shared_ptr对象供外部使用
class A:public enable_shared_from_this<A>{
public:
shared_ptr<A> getSelf(){
return shared_from_this();
}
};
int main(){
shared_ptr<A> ptr1(new A());
shared_ptr<A> ptr2=ptr1->getSelf();
return 0;
}
- 应避免enable_shared_from_this的循环引用问题
std::weak_ptr
- shared_ptr的Observer对象
- 只对shared_ptr进行引用,而不改变其引用计数
- 当被观察的shared_ptr失效后,相应的weak_ptr也相应失效
- 可用来解决shared_ptr相互引用时的死锁问题
- 初始化
shared_ptr<T> sPtr(new T(value));
weak_ptr<T> wPtr(sPtr);
shared_ptr<T> sPtr(new T(value));
weak_ptr<T> wPtr=sPtr;
- 没有重写->和*,也没有get()函数,因此不能直接操作对象
- 检测shared_ptr
if (wPtr.expired()) return;//返回true说明其引用的资源已经不存在了
shared_ptr<T> sPtr=wPtr.lock();
if(sPtr){
//对sPtr进行操作
}
- eg.观察者模式
class Subscriber{
};
class SubscribeManager{
public:
void publish(){
for(const auto &iter : m_subscribers){
if (!iter.expired()){
//给订阅者发送消息
}
}
}
private:
vector<weak_ptr<Subscriber> > m_subscribers;
};
使用原则
- 一旦一个对象使用智能指针管理后,就不该再使用原始裸指针去操作
- 作为类成员变量时,应该优先使用前置声明