c++11/14新特性---智能指针
智能指针
C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用。
智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。(因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。)
auto_ptr(C++98的方案,C++11已经抛弃)
auto_ptr<string> p1 (new string ("I reigned lonely as a cloud."));
auto_ptr<string> p2;
p2 = p1; // auto_ptr不会报错.
此时不会报错,p2剥夺了p1的所有权,但是当程序运行时访问p1将会报错。所以auto_ptr的缺点是:存在潜在的内存崩溃问题!
unique_ptr
unique_ptr实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露(例如“以new创建对象后因为发生异常而忘记调用delete”)特别有用。
unique_ptr<string> p3 (new string ("auto")); //#4
unique_ptr<string> p4; //#5
p4 = p3; // 此时会报错!!
当程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;
如果源 unique_ptr 将存在一段时间,编译器将禁止这么做,比如:
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1; // #1 不允许
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You")); // #2 允许
如果确实想执行类似与#1的操作,要安全的重用这种指针,可给它赋新值。
C++有一个标准库函数std::move(),让你能够将一个unique_ptr赋给另一个。
尽管转移所有权后 还是有可能出现原有指针调用(调用就崩溃)的情况。
但是这个语法能强调你是在转移所有权,让你清晰的知道自己在做什么,从而不乱调用原有指针。如:
unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;
shared_ptr
C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。
该引用计数的内存在堆上分配。
当新增一个时引用计数加1,当过期时引用计数减一。只有引用计数为0时,智能指针才会自动释放引用的内存资源。
对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。
shared_ptr 管理动态数组时,可以指定删除器

我们可以指定删除器:shared_ptr<Test> p1(new Test[5], default_delete<Test[]>());
当然也可以指定类型(c++11是不支持的):shared_ptr<Test[]> p1(new Test[5]);
weak_ptr
share_ptr虽然已经很好用了,但是有一点share_ptr智能指针还是有内存泄露的情况,如果在一个类中编写了一个函数,通过这个得到管理当前对象的共享智能指针:
#include <iostream>
#include <memory>
using namespace std;
struct Test
{
shared_ptr<Test> getSharedPtr()
{
return shared_ptr<Test>(this);
}
~Test()
{
cout << "class Test is disstruct ..." << endl;
}
};
int main()
{
shared_ptr<Test> sp1(new Test);
cout << "use_count: " << sp1.use_count() << endl;
shared_ptr<Test> sp2 = sp1->getSharedPtr();
cout << "use_count: " << sp1.use_count() << endl;
return 0;
}
结果一个对象会被析构了两次,在这个例子中使用同一个指针 this 构造了两个智能指针对象 sp1 和 sp2,这二者之间是没有任何关系的,因为 sp2 并不是通过 sp1 初始化得到的实例对象。在离开作用域之后 this 将被构造的两个智能指针各自析构,导致重复析构的错误。
这个问题可以通过 weak_ptr 来解决,通过 weak_ptr 返回管理 this 资源的共享智能指针对象 shared_ptr。C++11 中为我们提供了一个模板类叫做 std::enable_shared_from_this<T>,这个类中有一个方法叫做 shared_from_this(),通过这个方法可以返回一个共享智能指针,在函数的内部就是使用 weak_ptr 来监测 this 对象,并通过调用 weak_ptr 的 lock() 方法返回一个 shared_ptr 对象。
#include <iostream>
#include <memory>
using namespace std;
struct Test : public enable_shared_from_this<Test>
{
shared_ptr<Test> getSharedPtr()
{
return shared_from_this();
}
~Test()
{
cout << "class Test is disstruct ..." << endl;
}
};
int main()
{
shared_ptr<Test> sp1(new Test);
cout << "use_count: " << sp1.use_count() << endl;
shared_ptr<Test> sp2 = sp1->getSharedPtr();
cout << "use_count: " << sp1.use_count() << endl;
return 0;
}
当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
class B; // 声明
class A
{
public:
shared_ptr<B> pb_;
~A()
{
cout << "A delete\n";
}
};
class B
{
public:
shared_ptr<A> pa_;
~B()
{
cout << "B delete\n";
}
};
void fun()
{
shared_ptr<B> pb(new B());
shared_ptr<A> pa(new A());
cout << pb.use_count() << endl; // 1
cout << pa.use_count() << endl; // 1
pb->pa_ = pa;
pa->pb_ = pb;
cout << pb.use_count() << endl; // 2
cout << pa.use_count() << endl; // 2
}
int main()
{
fun();
return 0;
}
将shared_ptr<B> pb_;和shared_ptr<A> pa_;都换成weak_ptr就没问题了。
weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr,所以在使用weak_ptr之前可以先调用lock尝试转化为shared_ptr,来查看指向的指针是否有效。
weak_ptr<int> p2;
{
shared_ptr<int> p1(new int(1));
p2 = p1;
}
shared_ptr<int> p3 = p2.lock();
if (p3)
{
cout << *p3 << endl;
}
else
{
cout << "null" << endl;
}
如果不知道p1有没有被释放掉了,p2使用的时候可以先提升一下成为p3,再做后续操作。
简单实现
class Counter
{
public:
Counter() : s(0), w(0){};
int s; // share_ptr的引用计数
int w; // weak_ptr的引用计数
};
counter对象的目地就是用来申请一个块内存来存引用基数,s是share_ptr的引用计数,w是weak_ptr的引用计数,当w为0时,删除Counter对象。
template <class T>
class WeakPtr; //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
template <class T>
class SharePtr
{
public:
SharePtr(T *p = 0) : _ptr(p)
{
cnt = new Counter();
if (p)
cnt->s = 1;
cout << "in construct " << cnt->s << endl;
}
~SharePtr()
{
release();
}
SharePtr(SharePtr<T> const &s)
{
cout << "in copy con" << endl;
_ptr = s._ptr;
(s.cnt)->s++;
cout << "copy construct" << (s.cnt)->s << endl;
cnt = s.cnt;
}
SharePtr(WeakPtr<T> const &w) //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
{
cout << "in w copy con " << endl;
_ptr = w._ptr;
(w.cnt)->s++;
cout << "copy w construct" << (w.cnt)->s << endl;
cnt = w.cnt;
}
SharePtr<T> &operator=(SharePtr<T> &s)
{
if (this != &s)
{
release();
(s.cnt)->s++;
cout << "assign construct " << (s.cnt)->s << endl;
cnt = s.cnt;
_ptr = s._ptr;
}
return *this;
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
friend class WeakPtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
protected:
void release()
{
cnt->s--;
cout << "release " << cnt->s << endl;
if (cnt->s < 1)
{
delete _ptr;
if (cnt->w < 1)
{
delete cnt;
cnt = NULL;
}
}
}
private:
T *_ptr;
Counter *cnt;
};
template <class T>
class WeakPtr
{
public: //给出默认构造和拷贝构造,其中拷贝构造不能有从原始指针进行构造
WeakPtr()
{
_ptr = 0;
cnt = 0;
}
WeakPtr(SharePtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
{
cout << "w con s" << endl;
cnt->w++;
}
WeakPtr(WeakPtr<T> &w) : _ptr(w._ptr), cnt(w.cnt)
{
cnt->w++;
}
~WeakPtr()
{
release();
}
WeakPtr<T> &operator=(WeakPtr<T> &w)
{
if (this != &w)
{
release();
cnt = w.cnt;
cnt->w++;
_ptr = w._ptr;
}
return *this;
}
WeakPtr<T> &operator=(SharePtr<T> &s)
{
cout << "w = s" << endl;
release();
cnt = s.cnt;
cnt->w++;
_ptr = s._ptr;
return *this;
}
SharePtr<T> lock()
{
return SharePtr<T>(*this);
}
bool expired()
{
if (cnt)
{
if (cnt->s > 0)
{
cout << "empty" << cnt->s << endl;
return false;
}
}
return true;
}
friend class SharePtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
protected:
void release()
{
if (cnt)
{
cnt->w--;
cout << "weakptr release" << cnt->w << endl;
if (cnt->w < 1 && cnt->s < 1)
{
//delete cnt;
cnt = NULL;
}
}
}
private:
T *_ptr;
Counter *cnt;
};
更多推荐
所有评论(0)