C++智能指针原理及简略使用
智能指针
来点现代C++教程:
https://changkun.de/modern-cpp/zh-cn/05-pointers/
https://www.cnblogs.com/wxquare/p/4759020.html
shared_ptr
核心是RAII(资源获取即初始化),实现的核心机制是线程安全的引用技术和临界区保护
shared_ptr的引用计数是线程安全的,但是shared_ptr本身进行修改时不是线程安全的。
std::shared_ptr<int> ptr = std::make_shared<int>(10);
// 如果两个线程同时执行以下代码是不安全的
ptr = std::make_shared<int>(20);
保护方式:
- 互斥锁mutex
- 原子量
std::atomic<std::shared_ptr<T>>
- 单线程
注意,只有通过拷贝或者移动语义才能够增加引用计数,重复make不会
int a = 10;
//assert(a != 10);
shared_ptr<int> sptr10 = make_shared<int>(a);
shared_ptr<int> sptr11 = make_shared<int>(a);
cout<<sptr10.use_count()<<endl;
cout<<sptr11.use_count()<<endl;
输出为:
1
1
unique_ptr
release之后原有的指针仍然存在(14标准也有make_unique
)
unique移动之后原有的unique ptr指针变为0,避免了出现悬垂指针
weak_ptr
-
expired(): 判断是否全部消除,等价于use_count()==0
-
lock(): 返回一个shared ptr,增加引用计数
-
强引用:增加引用计数
-
弱引用:不增加引用计数
一个重要的问题是避免shared_ptr循环引用,最典型的例子是
外部两个shared ptr指向两个不同的类,两个不同的类内部有shared ptr指向彼此(parent和child关系)
方法是将类中一个改为weak,外部不变
示例代码:
#include<iostream>
#include<memory>
using namespace std;
class test{
private:
int i;
public:
test(int x) {
cout<<"create"<<endl;
i = x;
}
~test() {
cout<<"destroy"<<endl;
}
int geti() {
return i;
}
};
int main() {
shared_ptr<test> sptr1 = make_shared<test>(5);
auto sptr2 = sptr1;
cout<<sptr1.get()->geti()<<endl;
cout<<sptr1.use_count()<<endl;
cout<<sptr2->geti()<<endl;
test* t = new test(10);
unique_ptr<test> uptr1(t);
cout<<uptr1->geti()<<endl;
cout<<"\n--------------------------------\n";
auto uptr2 = move(uptr1);
cout<<uptr2->geti()<<endl;
cout<<reinterpret_cast<long long>(uptr1.get())<<endl; // 0
cout<<reinterpret_cast<long long>(uptr2.get())<<endl; // not 0
uptr2.release();
cout<<reinterpret_cast<long long>(uptr2.get())<<endl; // 0
// no automatic release
// origin pointer still exists
unique_ptr<test> uptr3(t);
cout<<uptr3->geti()<<endl;
unique_ptr<test> uptr4 = make_unique<test>(15);
cout<<uptr4->geti()<<endl;
cout<<"\n--------------------------------\n";
weak_ptr<test> wptr1(sptr1);
cout<<wptr1.use_count()<<endl; // 2
cout<<wptr1.expired()<<endl;
if(!wptr1.expired()) {
shared_ptr<test> ptrx = wptr1.lock(); // shared
cout<<wptr1.use_count()<<endl; // 3
cout<<sptr1.use_count()<<endl; // 3
}
return 0;
}
面试实战:***后端开发一面,实现shared_ptr
弱智的点在于我当时实在想不出来引用计数怎么实现,直接static了,最后毫无疑问的挂掉了