智能指针3:带引用计数的智能指针(weak_ptr、shared_ptr)

带引用计数的智能指针

1、shared_ptr强智能指针

  • 共享式智能指针,可以多个智能指针指向同一个内存,每次拷贝构造和赋值都会让引用计数+1,每次释放一个对象会让引用计数-1,只有当引用计数为0的时候,堆内存资源才会释放;

  • 基本使用:

    • 初始化:
      #include
      //初始化方式1
      std::shared_ptr<int> sp1(new int(123));
      
      //初始化方式2
      std::shared_ptr<int> sp2;
      sp2.reset(new int(123));
      
      //初始化方式3
      std::shared_ptr<int> sp3;
      sp3 = std::make_shared<int>(123);;
      
  • TIP:

    • 同一个普通的智能指针不能给多个shared_ptr赋值,会导致内存重复释放

2、weak_ptr弱智能指针

  • 弱智能指针,不能改变资源的引用计数,也就是不控制资源的声明周期,只是观察资源,不能访问资源,没有提供operator*operator->重载,使用来配合shared_ptr来使用的。

  • 如果需要使用资源的时候,可以将weak_ptr通过成员方法lock()提升为shared_ptr:

        void func()
        {
            shared_ptr<A> ps = _ptra.lock();  //ps出函数作用域析构
            if (ps != nullptr) //判断释放成功,成功了给对象引用计数+1
            {
                ps->testA();
            }
        }
    

3、智能指针交叉引用问题

#include
#include
using namespace std;
class B;
class A
{
public:
    A() { cout << "A()" << endl; }
    ~A() { cout << "~A()" << endl; }
   	shared_ptr<B> _ptrb; //引用对象,应该用弱智能指针
    void testA() { cout << "非常好用的方法" << endl; }
};
class B
{
public:
    B() { cout << "B()" << endl; }
    ~B() { cout << "~B()" << endl; }
    shared_ptr<A> _ptra;
};

int main()
{
    //定义对象
    shared_ptr<A> pa(new A());
    shared_ptr<B> pb(new B());
    cout << pa.use_count() << endl; // 1
    cout << pb.use_count() << endl;// 1
    
    pa->_ptrb = pb; //引用计数+1
    pb->_ptra = pa;//引用计数+1
    cout << pa.use_count() << endl; // 2
    cout << pb.use_count() << endl; // 2
    return 0;
}
	/*完成的输出,并没有调用A、B的析构
	A()
	B()
	1
	1
	2
	2
	*/
	原因:
	由于堆上对象A、B的引用计数为2,出main只是析构pa、pb,引用计数-1,而A、B还没被各自
	类成员_ptrb、_ptra所引用,由于A、B在堆上,对应的_ptrb、_ptra也在堆上
	_ptrb、_ptra得不到释放,因此A、B也无法调用析构
	解法:
	在类里面使用弱智能指针weak_ptr,不改变引用计数

4、智能指针的大小

#include
#include
using namespace std;
int main()
{
    int* p;
    shared_ptr<int> p1(new int);
    weak_ptr<int> p2(p1);
    unique_ptr<int> p3;
    cout << sizeof(p) << endl; // x86:4,x64:8
    cout << sizeof(p1) << endl;// x86:8,x64:16
    cout << sizeof(p2) << endl;// x86:8,x64:16
    cout << sizeof(p3) << endl; // x86:4,x64:8
	/*
	unique_ptr和裸指针一样大小
	shared_ptr和weak_ptr是裸指针的两倍
	*/
    return 0;
}

TIP

  • 通过智能指针还可以解决线程安全问题,多线程中可以通过weak_ptr判断对应的对象是不是还存活,从而使用在多线程中访问对象方法
  • 如果用智能指针封装的不是普通的指针,就需要自己定义删除器,比如文件句柄等
  • get()成员方法返回的是裸指针,需要小心使用
  • 不要用原始指针给多个shared_ptr赋值,会导致堆内存重复释放
  • 智能指针管理的是堆上的对象,不是栈上的对象

你可能感兴趣的:(C++基础学习,智能指针,c++)