智能指针之共享指针shared

    科技2024-07-18  76

    @著作权归作者所有:来自博客作者大胡子的艾娃的原创作品,如需转载,请注明出处https://blog.csdn.net/qq_43148810,否则将追究法律责任。 如有错误的地方欢迎指正,谢谢!

    class MyClass { public: MyClass(int m = 0) :M(m){ std::cout << "构造 " << M << std::endl; } MyClass(MyClass& myC) :M(myC.M){ std::cout << "拷贝构造 " << M << std::endl; } ~MyClass(){ std::cout << "析构 " << M << std::endl; } const int get_Date()const{ return this->M; } private: int M; }; void del_MyClass(MyClass* myC){ std::cout << "自定义删除器 " << std::endl; return delete myC; } void del_Array_MyClass(MyClass* myC){ std::cout << "自定义数组删除器 " << std::endl; return delete[] myC; } class Class_Delete { public: void operator()(MyClass* myC){ std::cout << "自定义仿函数删除器 " << std::endl; return delete myC; } }; class Class_Delete_A { public: void operator()(MyClass* myC) { std::cout << "自定义数组仿函数删除器 " << std::endl; return delete[] myC; } }; 一.shared_ptr public _Ptr_base<_Ty> 共享式智能指针:多个智能指针指向相同对象,该对象和其相关资源会在"最后一个reference被销毁"时被释放。 支持定制删除器,可防范Cross—DLL问题、自动解除互斥锁 1.创建的方式 MyClass myC1(1), myC2(2), myC3(3); MyClass* myC_p = new MyClass(4); //方式一:默认、空的 std::shared_ptr<MyClass> Str_ptr; //std::shared_ptr<MyClass> Str_ptr(nullptr); //方式二:make_shared传入对象 std::shared_ptr<MyClass> Str_ptr1 = std::make_shared<MyClass>(myC1); //方式三:直接传入一个对象的指针 std::shared_ptr<MyClass> Str_ptr2(new MyClass(myC2)); //std::shared_ptr<MyClass> Str_ptr2{ new MyClass(myC2) }; //std::shared_ptr<MyClass> Str_ptr2(myC_p); //方式四:reset一个对象的指针 std::shared_ptr<MyClass> Str_ptr3;Str_ptr3.reset(new MyClass(myC3)); //Str_ptr3.reset();放弃之前对象所有权,并将智能指针初始化为空 //Str_ptr3.reset(ptr);放弃之前对象所有权(默认删除器),并用ptr重新初始化Str_ptr3 //reset()的第二参数为删除器,第三参数为分配器 //方式五:创建与Str_ptr1共享的Str_ptr4智能指针,引用计数(use_count()返回值)增加 std::shared_ptr<MyClass> Str_ptr4(Str_ptr1); //std::shared_ptr<MyClass> Str_ptr5(move(Str_ptr2)); //方式六:从其他类型智能指针创建 std::shared_ptr<MyClass> Str_ptr5(weak_ptr); //std::shared_ptr<MyClass> Str_ptr5(move(unique_ptr)); //std::shared_ptr<MyClass> Str_ptr5(move(auto_ptr)); //方式七:别名构造 std::shared_ptr<MyClass> Str_ptr6(Str_ptr1,myC_p);//myC_p需要手动释放 //myC_p将赋值给成员element_type * _Ptr{nullptr}; //Str_ptr1的成员_Rep将赋值给成员_Ref_count_base * _Rep{nullptr}; 【注意】方式7很特殊。 一般std::shared_ptr<MyClass> Str_ptr()第二参数为删除器,第三参数为分配器 2.共享指针的强制转换类型转换运算符 1)static_pointer_cast 2)dynamic_pointer_cast 3)const_pointer_cast 3.线程安全接口 bool atomic_is_lock_free(const shared_ptr<_Ty> * _Ptr);//如果shared_ptr<_Ty>的原子操作是无锁的,则返回true shared_ptr<_Ty> atomic_load(const shared_ptr<_Ty> * _Ptr);//返回_Ptr void atomic_store(shared_ptr<_Ty> * _Ptr, shared_ptr<_Ty> _Other);//原子地将_Other存储到*_Ptr shared_ptr<_Ty> atomic_exchange(shared_ptr<_Ty> * _Ptr, shared_ptr<_Ty> _Other);//将_Other复制到*_Ptr并原子地返回之前的值*_Ptr 4.可选自定义删除器(有默认删除器)、数组 1)void del_MyClass(T* _myClass){ return delete _myClass; } std::shared_ptr<MyClass> Str_ptr4(new MyClass(4), del_MyClass); //自定义 或std::shared_ptr<MyClass> Str_ptr4(myC_p, std::default_delete<MyClass>()); 2)void del_Array_MyClass(MyClass* myC){ return delete[] myC; } //自定义 std::shared_ptr<MyClass> Str_ptr5(new MyClass[2], del_Array_MyClass); 或std::shared_ptr<MyClass> Str_ptr5(new MyClass[2], std::default_delete<MyClass[]>()); 3)std::shared_ptr<MyClass> sh_ptr_a(new MyClass[2], Class_Delete_A()); 4)std::shared_ptr<MyClass[]> sh_ptr_a(new MyClass[2]); //<>内为MyClass[]时,释放时能正确调用delete[] 5)std::shared_ptr<MyClass> sh_ptr_a(new MyClass[2]);是错误的,因为默认删除器调用的是delete6)自定义删除器可以是函数、lambda表达式、仿函数(函数对象)。调用处也可以使用函数指针。 7)针对数组不能使用*->原算符,要使用[]原算符,要使用运算符。 8)需要释放除对象以外的相关资源,必须要自定义删除器。 5.错误使用 多个共享智能指针共享同一对象,但不能拥有同一个对象,否则会出现使用已析构的对象 MyClass* myC_p = new MyClass(4); std::shared_ptr<MyClass> Str_ptr4(myC_p); std::shared_ptr<MyClass> Str_ptr5(myC_p); 6.共享指针存在问题 1)循环引用 2)明确想要共享但不拥有对象 二.weak_ptr

    public _Ptr_base<_Ty> 弱指针是共享指针的辅助类,允许共享但不拥有某对象,不会关联对象的引用次数。 不能使用运算符*和->直接访问弱指针的引用对象,而是通过Lock函数生成对象的共享指针(可能为空) 当拥有该对象的最后一个共享指针失去其所有权时,任何弱指针都会自动变为空。 weak_ptr除default和copy构造函数外,只提供"接受一个shared_ptr"的构造函数。 可打破环状引用(循环引用)

    1.确定弱指针指向的对象是否存在 1)调用use_count()来询问关联对象拥有的所有者数量。 2)调用expired(),等效于检查use_count()是否等于0。 3)使用共享指针构造函数将弱指针显示转换为共享指针。若无有效引用,此构造函数将引发bad_weak_ptr异常。

    2.特殊成员函数 1)lock();返回共享指针 2)运算法符重载为类的成员函数,按实现分为针对智能指针的(=)、拥有的对象的(类的成员*,->,[]等,全局的==,<,!=等比较运算法)。 3)owner_before(const _Ptr_base<_Ty2>& _Right)//比较管理器对象(共享指针或弱指针)的地址

    三.unique_ptr

    public _Unique_ptr_base<_Ty, _Dx> 异常时可以帮助避免资源泄漏的智能指针。 采用独占式拥有,意味着可以确保一个对象和其相应的资源同一时间只被一个 pointer拥有。 一旦拥有着被销毁或编程empty,或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。 unique_ptr 用于取代 auto_ptr

    1.检查独占式指针是否拥有对象 1)调用操作符bool() 2)与nullptr比较 3)获取原始指针再进行空判

    2.独占式智能指针特性 1)独占式智能指针unique_ptr类无"拷贝构造"(右值引用可以)、无"=运算重载"(右值引用可以,nullptr可以),保证唯一性。 2)同一指针不能初始化两个独占式指针。 3)move()函数转交所有权,拥有新的对象的所有权会释放之前所有权的对象。 4)独占式指针作函数形参,调用该函数的独占式指针实参要使用move函数。 //性能低,无意义,直接使用一般类型 但是作为返回值却可以直接将该函数内创建的独占式指针直接返回。并在调用处直接用独占式指针接受。 //不推荐使用

    3.异常时可以帮助避免资源泄漏的智能指针 #唯一指针有助于避免对象初始化期间引发的异常引起的资源泄漏

    4.可选自定义删除器(有默认删除器)、数组 1)除使用自定义删除器与共享指针不同,其他一致,参照共享指针。 2)std::unique_ptr<MyClass, void()(MyClass)> un_ptr1(new MyClass(2), del_MyClass); //std::unique_ptr<MyClass, Class_Delete> un_ptr2(new MyClass(2), Class_Delete()); std::unique_ptr<MyClass, Class_Delete> un_ptr2(new MyClass(2)); 3)std::unique_ptr<MyClass[], void()(MyClass)> un_ptr_a1(new MyClass[3], del_Array_MyClass); //std::unique_ptr<MyClass, Class_Delete_A> un_ptr_a2(new MyClass[2], Class_Delete_A()); //std::unique_ptr<MyClass[], Class_Delete_A> un_ptr_a2(new MyClass[2]); 【总结】: unique_ptr设置自定义删除器需要在第二模板参数传入自定义删除器的类型。 自定义删除器为仿函数的时候,构造函数初始化参数"class()"可以不传,共享指针无第二模板参数,必须传入。 无设置自定义删除器时,第一模板参数"T或T[]"必须与构造函数第一参数"new或new[]"相对应; 在已设置自定义删除器时,则无需相对应,但是构造函数第一参数必须和自定义删除器"delete或delete[]"与之相对应。

    四.auto_ptr auto_ptr可以进行赋值拷贝,赋值拷贝后所有权转移。 unique_ptr无拷贝赋值语义,但实现了move语义。 auto_ptr对象不能管理数组(析构调用delete),而unique_ptr可以。 等瑕疵 被C++11弃用

    更多内容请关注个人博客:https://blog.csdn.net/qq_43148810

    Processed: 0.012, SQL: 9