最近在看《C++ primer》第五版,试图学习一点C++11的特性。因为在C++中动态数组需要new和delete,很容易出现忘记delete的情况,也有可能在尚有指针的情况下释放,导致引用非法的空指针,所以引入了智能指针。
shared_ptr
shared_ptr类和make_shared函数
- 类似于vector,智能指针也是一种模板
- 解引用一个智能指针的方式和普通指针类似
例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <memory> #include <string>
using namespace std;
int main() { shared_ptr<string> p1 = make_shared<string>(""); if (p1 && p1->empty()) { *p1 = "Hi"; } cout << *p1 << endl; }
|
shared_ptr 的拷贝和赋值
进行拷贝或赋值操作的时候,shared_ptr中的会有一个计数器来记录有多少个其他的shared_ptr指向相同的对象,和Java的引用计数法很相似。
1 2
| auto p = make_shared<int>(42) auto q(p)
|
计数器变为0的时候,会自动释放所管理的对象,如下:
1 2
| auto r = make_shared<int>(42) r = q
|
shared_ptr和new结合使用
1 2
| shared_ptr<int> p1 = new int(1024); shared_ptr<int> p2(new int(1024));
|
一般情况下,一个用来初始化智能指针的普通指针必须指向动态内存。
不过不要混合使用普通指针和智能指针,原因如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <iostream> #include <memory> #include <string>
using namespace std;
void process(shared_ptr<int> ptr) { }
int main() { int* x(new int(24)); cout << *x << endl; process(shared_ptr<int>(x)); cout << *x << endl; }
|
在这里面,进入process之后,由普通指针初始化的智能指针由于有一份拷贝了,引用计数为1,结束过程的时候,引用计数减1,变为0,释放内存,所以这段代码的结果如下:
x在process结束后就被释放了。
也不要用get获取指针然后来再来创建智能指针,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <memory> #include <string>
using namespace std;
int main() { shared_ptr<int> p(new int(42)); int* q = p.get(); cout << *p << endl; { shared_ptr<int> x(q); } cout << *p << endl; }
|
这样的结果和上面的类似,就是会访问被释放的内存。
reset
可以用reset操作来更新智能指针
这样就可以顺利地改变智能指针的值了,同时更新引用计数。
unique_ptr
与shared_ptr不同,unique_ptr在同一时刻只能有一个unique_ptr指向指定的对象。
u.release()方法可以放弃对指针的控制权并返回指针
u.reset()释放u指向的对象,
u.reset(q)/u.reset(nullptr)如果提供了普通指针q,令u指向找个对象,否则u置为空
weak_ptr
不控制所指向对象生存期的智能指针,与shared_ptr类似,但是不会受引用计数影响,也不会影响引用计数。
智能指针循环引用问题
参考了https://www.cnblogs.com/64open/p/4826765.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class B; class A { public: shared_ptr<B> p; };
class B { public: shared_ptr<A> p; };
int main() { while (true) { shared_ptr<A> pa(new A()); shared_ptr<B> pb(new B()); pa->p = pb; pb->p = pa; } return 0; }
|
用weak_ptr就可以看出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <iostream> #include <memory> #include <string>
using namespace std; class B; class A { public: shared_ptr<B> ptr; };
class B { public: shared_ptr<A> ptr; };
int main() { weak_ptr<A> test; { shared_ptr<A> pa(new A()); shared_ptr<B> pb(new B()); pa->ptr = pb; pb->ptr = pa; test = pa; cout << test.use_count() << endl; } cout << test.use_count() << endl; return 0; }
|
两次cout分别为2和1,可以看出问题了。