再探 智能指针

网友投稿 624 2022-05-30

使用任何一项工具,都需要承担代价与风险的。

1、一个裸的指针不要用两个shared_ptr管理,unique_ptr也是,它们都会认为自己独占这个资源,你等释放的时候试试看。

2、用weak_ptr打破循环引用。

3、当需要在类的内部接口中,如果需要将this作为智能指针来使用的话,需要用该类派生自enable_shared_from_this。

enable_shared_from_this和shared_from_this在构造和析构中是不能使用的,在某些情况下也不能使用,因为构造的时候类还未生成好,析构的时候类快完蛋了都没有意义。

#include #include #include class Parent; typedef std::shared_ptr ParentPtr; typedef std::weak_ptr WeakParentPtr; class Child : public std::enable_shared_from_this { public: WeakParentPtr father; ~Child(); Child(); void checkRelation(); }; typedef std::shared_ptr ChildPtr; typedef std::weak_ptr WeakChildPtr; class Parent : public std::enable_shared_from_this { public: WeakChildPtr son; ~Parent(); Parent(); void checkRelation(); }; void handleChildAndParentRef(const Parent& p, const Child& c) { auto cp = c.father.lock(); auto pc = p.son.lock(); if (cp.get() == &p && pc.get() == &c) { std::cout << "right relation\n"; } else { std::cout << "oop!!!!!\n"; } } void handleChildAndParent(const ParentPtr& p, const ChildPtr& c) { auto cp = c->father.lock(); auto pc = p->son.lock(); if (cp == p && pc == c) { std::cout << "right relation\n"; } else { std::cout << "oop!!!!!\n"; } } Child::Child() { std::cout << "hello child\n"; } Parent::Parent() { std::cout << "hello parent\n"; } Child::~Child() { std::cout << "bye child\n"; } Parent::~Parent() { std::cout << "bye parent\n"; } void Parent::checkRelation() { auto ps = son.lock(); if (ps) { // this handleChildAndParent(shared_from_this(), ps); } std::cout << "after call checkRelation\n"; } void Child::checkRelation() { // we call handleChildAndParent } void testParentAndChild() { Parent pp; ParentPtr p(new Parent()); ChildPtr c(new Child()); p->son = c; // c.use_count() == 2 and p.use_count() == 1 c->father = p; // c.use_count() == 2 p.use_count() == 2 p->checkRelation(); } int main() { testParentAndChild(); }

4、shared_ptr,weak_ptr和裸指针相比会大很多,并且效率上会有影响,尤其是在多线程模式下。

再探 智能指针

关于这点自己实现一个智能指针就知道了。

一个shared_ptr在空间上至少是三个裸指针的大小(24个字节),本身有引用还要配合weak_ptr使用所以要保存多少该指针的引用。如下生成既有对象的new还有本身的new:

ObjectPtr obj3(new Object(2));

ObjectPtr obj4 = obj3进行拷贝时时间效率会慢很多

可以用以下方式减少空间

ObjectPtr obj5 = std::make_shared(3); //ObjectPtr obj5(new Object(3));

5、如果有可能,优先使用类的实例,其次万不得已使用std::unique_ptr,再万不得已使用std:shared_ptr。

用unique_ptr和用shared_ptr一样为了防止处理某些异常时无法调用delete释放资源的情况,在同一个特定的时刻只会有一个unique_ptr来管理一份资源没有共享模式,所以拷贝构造函数,=符号拷贝操作等是不存在的。

由于unique_ptr的唯一性所以要转移资源可以transfer传值,只能调用obj的右值引用而不能用左值,transfer函数执行完就释放了,调用了transfer后原有的会变成空指针不再管理。

#include #include #include typedef int Object; typedef std::unique_ptr UniqueObjectPtr; typedef std::shared_ptr SharedObjectPtr; void print(const UniqueObjectPtr& obj) {} void transfer(UniqueObjectPtr obj) { std::cout << obj << std::endl; } void uniquePtr() { UniqueObjectPtr obj(new Object(1)); auto p = obj.get(); // operator bool if (p) { std::cout << p << std::endl; } // better if (obj) { std::cout << obj << std::endl; } // operator -> * std::cout << p << obj << std::endl; p = obj.release(); delete p; obj.reset(); obj.reset(new Object(2)); // obj.reset(); // UniqueObjectPtr(const UniqueObjectPtr&) = delete // UniqueObjectPtr(UniqueObjectPtr&&) = default transfer(std::move(obj)); assert(obj == nullptr); //std::cout << obj->id() << std::endl; obj.reset(new Object(4)); SharedObjectPtr sharedObj(std::move(obj)); assert(obj == nullptr); // shared_ptr weak_ptr enable_shared_from_this // unique_ptr }

6、智能指针只能表示所有权,如果遇到某些复杂的数据结构,或者所有权不明确的场景,还是得裸指针来。

也很好举例,用智能指针写个二叉树试试。

好了就说到这儿吧,再说多了怕是以后都不敢用了。

今天之所以要写这么一篇,是最近看智能指针的好处被吹的天花乱坠的让我都有点想把以前裸指针的代码全改成智能指针了。

但是呢,不要忘了我们开头的那句话哦。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:内存、栈、堆
下一篇:使用DLI Flink SQL进行电商实时业务数据分析的操作感想
相关文章