std::shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存,在最后一个shared_ptr析构的时候,内存才会释放。ios
shared_ptr能够经过make_shared来初始化,也能够经过shared_ptr<T>辅助函数和reset方法来初始化。智能指针的用法和普通指针的用法相似,不过不须要本身管理分配的内存,对于没有初始化的指针,只能经过reset来初始化,当智能指针有值,reset会使计数器减1。智能指针能够经过重载的bool来判断是否为空。数组
#include <iostream> #include <memory> using namespace std; int main() { //智能指针初始化 shared_ptr<int> p = make_shared<int>(20); shared_ptr<int> p(new int(1)); shared_ptr<int> p1 = p; shared_ptr<int> ptr; //所指的对象会被重置,不带参数则是销毁 ptr.reset(new int(5)); if(ptr) { cout << "ptr is not null" << endl; } return 0; }
智能指针不能经过原始指针来初始化:安全
shared_ptr<int> p = new int(1); //编译报错,不能直接赋值
当须要获取原始指针的时候,能够经过get来返回原始指针。不能释放,若是释放会出错。函数
shared_ptr<int> ptr(new int(1)); int* p = ptr.get(); delete p; //error
智能指针支持指定删除器,在指针引用为0的时候自动调用。支持普通函数和lambda表达式。this
//普通函数 void DeleteIntPtr(int *p) {delete p;} shared_ptr<int> p(new int(10), DeleteIntPtr);
//lambda表达式 shared_ptr<int> p(new int(10), [](int *p) {delete p;});
当智能指针管理动态数组的时候,默认的删除器不支持数组对象。须要指定删除器,自定义删除器或者使用改善的默认修改器均可以。spa
shared_ptr<int> p(new int[10], [](int *p) {delete[] p;}); //lambda shared_ptr<int> p1(new int[10], default_delete<int []>); //指定delete []
a.避免一个原始指针初始化多个shared_ptr。指针
int* p = new int; shared_ptr<int> p1(p); shared_ptr<int> p2(p);
b.不要在参数实参中建立shared_ptr。code
func(shared_ptr<int>(new int), g());
不一样的编译器可能有不一样的调用约定,若是先new int,而后调用g(),在g()过程当中发生异常,可是shared_ptr没有建立,那么int的内存就会泄漏,正确的写法应该是先建立智能指针。对象
shared_ptr<int> p(new int); f(p, g());
c.避免循环使用,循环使用可能致使内存泄漏blog
#include <iostream> #include <memory> using namespace std; struct A; struct B; struct A { shared_ptr<B> bptr; ~A() { cout << "A is deleted." << endl; } }; struct B { shared_ptr<A> aptr; ~B() { cout << "B is deleted." << endl; } }; int main() { shared_ptr<A> ap(new A); shared_ptr<B> bp(new B); ap->bptr = bp; bp->aptr = ap; return 0; }
这个最经典的循环引用的场景,结果是两个指针A和B都不会删除,存在内存泄漏。循环引用致使ap和bp的引用计数为2,离开做用域以后,ap和bp的引用计数为1,并不会减0,致使两个指针都不会析构而产生内存泄漏。
d.经过shared_from_this()返回this指针。不要将this指针做为shared_ptr返回出来,由于this指针本质是一个裸指针,这样可能致使重复析构。
#include <iostream> #include <memory> using namespace std; struct A { shared_ptr<A> GetSelf() { return shared_ptr<A>(this); } ~A() { cout << "A is deleted." << endl; } }; int main() { shared_ptr<A> ap(new A); shared_ptr<A> ap2 = ap->GetSelf(); return 0; } //执行结果 A is deleted. A is deleted.
这个例子中,因为同一指针(this)构造了两个只能指针ap和ap2,而他们之间是没有任何关系的,在离开做用域以后this将会被构造的两个智能指针各自析构,致使重复析构的错误。固然,也有解决办法,解决办法在以后的weak_ptr介绍。
unique_ptr是一个独占型智能指针,它不容许其余的智能指针共享其内部的指针,不容许经过赋值将一个unique_ptr赋值给另外一个unique_ptr。只能经过函数来返回给其它的unique_ptr,好比move函数,可是转移以后,再也不对以前的指针具备全部权。
unique_ptr<int> uptr(new int(10)); unique_ptr<int> uptr2 = uptr; //error unique_ptr<int> uptr3 = move(uptr); //uptr将变为null
unique_ptr和shared_ptr相比除了独占以外,unique_ptr还能够指向一个数组。
unique_ptr<int []> ptr(new int[10]); //ok ptrp[1] = 10; shared_ptr<int []> ptr2(new int[10]); //error
unique_ptr必须指定删除器类型,不像shared_ptr那样直接指定删除器。
shared_ptr<int> ptr(new int(1), [](int *p){delete p;}); //ok unique_ptr<int> ptr2(new int(1), [](int *p){delete p;}); //error unique_ptr<int, void(*)(int *)> ptr2(new int(1), [](int *p){delete p;}); //ok
经过指定函数类型,而后经过lambda表达式实现是能够,可是若是捕获了变量将会编译报错,由于lambda表达式在没有捕获变量的状况下能够直接转换为函数指针,可是捕获了变量就没法转换。若是要支持,能够经过std::function来解决。
unique_ptr<int, void(*)(int *)> ptr2(new int(1), [&](int *p){delete p;}); //error unique_ptr<int, std::function<void(int*)>> ptr2(new int(1), [&](int *p){delete p;}); //ok
unique_ptr支持自定义删除器。
#include <iostream> #include <memory> #include <functional> using namespace std; struct DeleteUPtr { void operator()(int* p) { cout << "delete" << endl; delete p; } }; int main() { unique_ptr<int, DeleteUPtr> p(new int(1)); return 0; }
弱引用智能指针weak_ptr用来监视shared_ptr,不会使引用技术加1,也无论理shared_ptr内部的指针,主要是监视shared_ptr的生命周期。weak_ptr不共享指针,不能操做资源,它的构造和析构都不会改变引用计数。
经过use_count()方法来得到当前资源的引用计数。
shared_ptr<int> sp(new int(10)); weak_ptr<int> wp(sp); cout << wp.use_count() << endl; //输出1
shared_ptr<int> sp(new int(10)); weak_ptr<int> wp(sp); if(wp.expired()) { cout << "sp 已经释放,无效" << endl; } else { cout << "sp 有效" << endl; }
能够经过lock方法来获取所监视的shared_ptr。
#include <iostream> #include <memory> using namespace std; weak_ptr<int> gw; void f() { //监听是否释放 if(gw.expired()) { cout << "gw is expired." << endl; } else { auto spt = gw.lock(); cout << *spt << endl; } } int main() { { auto p = make_shared<int>(20); gw = p; f(); } f(); return 0; } //执行结果 20 gw is expired.
sharerd_ptr不能直接返回this指针,须要经过派生std::enable_shared_from_this类,并经过其方法shared_from_this来返回智能指针,由于std::enable_shared_from_this类中有一个weak_ptr,这个weak_ptr用来观测this指针,调用shared_from_this方法时,调用了内部的weak_ptr的lock()方法,将所观测的sharerd_ptr返回。
#include <iostream> #include <memory> using namespace std; struct A:public enable_shared_from_this<A> { shared_ptr<A> GetSelf() { return shared_from_this(); } ~A() { cout << "A is deleted." << endl; } }; int main() { shared_ptr<A> spy(new A); shared_ptr<A> p = spy->GetSelf(); //ok return 0; } //执行结果 A is deleted.
在外面建立A对象的智能指针经过该对象返回this的智能指针是安全的,由于shared_from_this()是内部weak_ptr调用lock()方法以后返回的智能指针,在离开做用域以后,spy的引用计数为0,A对象会被析构,不会出现A对象被析构两次的问题。
须要注意的是,获取自身智能指针的函数仅在share_ptr<T>的构造函数调用以后才能使用,由于enable_shared_from_this内部的weak_ptr只有经过shared_ptr才能构造。
shared_ptr的循环引用可能致使内存泄漏,以前的例子再也不赘述,经过weak_ptr能够解决这个问题,怎么解决呢?答案是,将A或者B任意一个成员变量改成weak_ptr便可。
#include <iostream> #include <memory> using namespace std; struct A; struct B; struct A { shared_ptr<B> bptr; ~A() { cout << "A is deleted." << endl; } }; struct B { weak_ptr<A> aptr; ~B() { cout << "B is deleted." << endl; } }; int main() { shared_ptr<A> ap(new A); shared_ptr<B> bp(new B); ap->bptr = bp; bp->aptr = ap; return 0; } //执行结果 A is deleted. B is deleted.
这样在对B成员赋值时,即bp->aptr = ap,因为aptr是weak_ptr,并不会增长引用计数,因此ap的计数仍然是1,在离开做用域以后,ap的引用计数会减为0,A指针会被析构,析构以后,其内部的bptr引用计数会减1,而后离开做用域以后,bp引用计数从1减为0,B对象也被析构,因此不会发生内存泄漏。