智能指针
文章目录
C++11 种提供了3种智能指针,使用时需要包含头文件
- std::shared_ptr: 共享智能指针
- std::unique_ptr: 独享的智能指针
- std::weak_ptr: 弱引用的智能指针,不共享指针,不操作资源,用来监视shared_ptr
shared_ptr
1、shared_ptr 的初始化
提供四种方式来进行初始化:
-
通过构造函数初始化, 如
std::shared_ptr<int> ptr1(new int); // std::shared_ptr<int > ptr2(new T()); //构造的同时,完成初始化内存;
shared_ptr<int> ptr1(new int); shared_ptr<int> ptr2(new int(123)); cout << ptr1.use_count() << " ptr1 value:"<< *ptr1 << "\n" << ptr2.use_count() << " ptr2 value:"<< *ptr2<< endl; // 输出:1 ptr1 value:0 1 ptr2 value:123
-
注意事项
- 可以初始化为空
shared_ptr<int> ptr; // 不管理任何内存,use_count = 0;
- shared_ptr ptr3 = new int(123); //error, 将调用拷贝构造函数,拷贝构造函数是explicit的.
- 可以初始化为空指针
shared_ptr<int> ptr(nullptr);
-
-
通过拷贝和移动构造函数初始化
shared_ptr<int> ptr1(new int(123)); shared_ptr<int> ptr2(ptr1); // 调用拷贝构造函数 shared_ptr<int> ptr3 = ptr1; // 调用拷贝构造函数 shared_ptr<int> ptr4(move(ptr3)); // 调用移动构造函数 shared_ptr<int> ptr5 = move((ptr4)); // 调用移动构造函数 cout << ptr1.use_count() << endl; cout << ptr3.use_count() << endl; cout << ptr4.use_count() << endl; cout << ptr5.use_count() << endl; //cout << *ptr4 << endl; // Segmentation fault, 已经不具有所有权 //输出: 3 0 0 3
-
通过make_shared 初始化
class A { public: A() { cout << "default construct" << endl; } A(int x) { cout << "int default construct" << endl; } A(string str) { cout << "string default construct" << endl; } ~A() { cout << "deconstruct ~" << endl; } }; void test03() { shared_ptr<int> ptr1 = make_shared<int>(520); cout << ptr1.use_count() << endl; shared_ptr<A> ptr2 = make_shared<A>(); shared_ptr<A> ptr3 = make_shared<A>(1); shared_ptr<A> ptr4 = make_shared<A>("abc"); } // 输出 1 default construct int default construct string default construct deconstruct ~ deconstruct ~ deconstruct ~
-
通过reset来初始化,对于一个未初始化的共享智能指针,可以通过reset方法来初始化,当智能指针中有值的时候,调用reset会使引用计数减1。
void test04() { shared_ptr<int> ptr; ptr.reset(new int(123)); cout << *ptr << endl; shared_ptr<int> ptr2 = make_shared<int>(1); shared_ptr<int> ptr3 = ptr2; ptr2.reset(); cout << ptr3.use_count() << " "<< ptr2.use_count() << endl; cout << *ptr3 << endl; // cout << *ptr2 << endl; //段错误,已经释放对内存的管理权 } //输出 123 1 0 1
2、原始指针
-
通过get() 获取,
-
可以通过release() 返回原始对象的指针
std::shared_ptr<int> ptr(new int(42)); int* rawPtr = ptr.release(); //释放指针并返回指向的内存地址 //现在,rawPtr指向原始内存,并且ptr不再管理该内存 delete rawPtr; //手动释放内存
3、reset()
- 使用该函数,引用计数减1, 不会再指向这个对象
4、release()
- release()方法返回当前shared_ptr中的指针,并将shared_ptr重置为空指针。这意味着shared_ptr不再管理该内存区域,并且不会自动删除该内存。
5、指定删除器
-
当管理动态数组内存时,需要指定删除器
void deleteInt(int* p) { delete []p; cout << "delete" << endl; } void test06() { shared_ptr<int> ptr(new int[10], deleteInt); shared_ptr<int> ptr2(new int[10], [](int* p) { delete []p; cout << "lambda delete" << endl; }); } //输出 lambda delete delete
-
使用默认的删除器
shared_ptr<int> ptr(new int[10], default_delete<int[]>());
unique_ptr()
unique_ptr是一个独占型的智能指针,不允许其他的智能指针共享内部的指针,不允许拷贝构造
1、初始化
-
初始化示例
unique_ptr<int> ptr(new int(10)); //unique_ptr<int> ptr2 = ptr ; // error
-
虽然不允许复制, 但是可以通过函数返回unique_ptr,也可以通过move转移
unique_ptr<int> ptr1(new int(10)); unique_ptr<int> ptr2 = move(ptr1); unique_ptr<int> ptr3 = func();
2、获取原始指针
- get()
3、reset()
-
解除对内存的管理
unique_ptr<int> ptr1(new int(10)); unique_ptr<int> ptr2 = move(ptr1); //cout << *ptr1 << endl; //Segmentation fault 已经释放, ptr1.reset(); ptr2.reset(new int(20));
4、指定删除器
-
unique_ptr和shared_ptr指定删除器是有区别的,unique_ptr指定删除器需要确定删除器的类型
shared_ptr<int> ptr1(new int[10], [](int* p) {delete []p;}) ;// error //unique_ptr<int> ptr1(new int[10], [](int* p) {delete []p;}) // error using func_ptr = void(*)(int *); unique_ptr<int, func_ptr> ptr2(new int[10], [](int* p) {delete []p;});
-
指定删除器有4种方法
-
函数指针
std::unique_ptr<int[], void(*)(int *)> ptr(new int[10], [](int *p) {delete p; });
上面写法没有在lambda中捕获变量,如果捕获将编译错误
std::unique_ptr<int[], void(*)(int *)> ptr(new int[10], [&](int *p) {delete p; }); // error
-
functional
unique_ptr<int, function<void(int*)> > ptr1(new int[10], [&](int*p) {delete []p;cout << "functional delete" << endl;});
-
使用仿函数
struct funDelete{ void operator()(int* p) { delete[] p; cout << "funDelete " << endl; } }; void test06() { unique_ptr<int, funDelete> p(new int[10]); }
-
默认删除器default_delete
unique_ptr<int[]> ptr(new int[10], default_delete<int[]>());
-
weak_ptr()
weak_ptr不管理shared_ptr内部的指针,没有重载操作符* 和->, 不共享指针,不能操作资源,它的构造不会增加引用计数,析构不会减少引用计数,主要是监视shared_ptr中管理的资源是否存在。
1、初始化
-
可以通过shared_ptr来构造
shared_ptr<int> ptr(new int(10)); weak_ptr<int> ptr2 = ptr;
-
构造空的weak_ptr
weak_ptr<int> wp1; weak_ptr<int> wp2(wp1);
2、use_count()
- 获取管理对象的引用计数,只监视,不管理资源
3、expired()
- 判断所观测的资源是否已经被释放,true表示已经释放, false表示没有被释放
4、lock()
-
通过lock 方法获取shared_ptr对象
shared_ptr<int> ptr = make_shared<int>(10); weak_ptr<int> wptr; wptr = ptr; shared_ptr<int> sp2 = wptr.lock(); cout << sp2.use_count() << endl; //输出 2
5、reset()
-
清空对象,使不监测任何资源
shared_ptr<int> ptr = make_shared<int>(19); weak_ptr<int> wptr = ptr; wptr.reset(); cout << wptr.expired() << endl; cout << *ptr << endl; // 输出 1 19
6、循环引用问题
-
shared_ptr 如果循环引用,可能导致内存泄露,所以引入weak_ptr
struct B; struct A { shared_ptr<B> mPtrB; ~A() { cout << "delete A" << endl; } }; struct B { shared_ptr<A> mPtrA; ~B() { cout << "delete B" << endl; } }; void test04() { shared_ptr<A> ptra(new A); shared_ptr<B> ptrb(new B); ptra->mPtrB = ptrb; ptrb->mPtrA = ptra; cout << ptra.use_count() << " " << ptrb.use_count() << endl; } // 输出2 2
-
改成weak_ptr
struct B; struct A { shared_ptr<B> mPtrB; ~A() { cout << "delete A" << endl; } }; struct B { weak_ptr<A> mPtrA; ~B() { cout << "delete B" << endl; } }; void test04() { shared_ptr<A> ptra(new A); shared_ptr<B> ptrb(new B); ptra->mPtrB = ptrb; ptrb->mPtrA = ptra; cout << ptra.use_count() << " " << ptrb.use_count() << endl; } //输出 1 2 delete A delete B
7、shared_from_this()
-
当一个类被共享智能指针 share_ptr 管理,且在类的成员函数里需要把当前类对象作为参数传给其他函数时,这时就需要传递一个指向自身的 share_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; } // 输出 use_count: 1 use_count: 2 class Test is disstruct ...
-
需要使用的原因:
#include <iostream> #include <memory> class Widget{ public: Widget(){ std::cout << "Widget constructor run" << std::endl; } ~Widget(){ std::cout << "Widget destructor run" << std::endl; } std::shared_ptr<Widget> GetSharedObject(){ return std::shared_ptr<Widget>(this); } }; int main() { std::shared_ptr<Widget> p(new Widget()); std::shared_ptr<Widget> q = p->GetSharedObject(); std::cout << p.use_count() << std::endl; std::cout << q.use_count() << std::endl; return 0; } // 输出 Widget constructor run 1 1 Widget destructor run Widget destructor run // 会析构两次
补充
-
shared_ptr 自身引用计数是线程安全的,但是指向的数据并不是线程安全的
-
unique_ptr没有use_count()函数。