C++11新特性之智能指针
2018-03-18 22:25
471 查看
本文章参考https://www.cnblogs.com/feng-sc/p/5710724.html#title33。因为其对智能指针介绍的比较详细,在自己的工作中,智能指针用的少,都是new delete用的多,实际开发中,不少情况下会出现内存泄漏的问题,都是因为只有new 没有delete导致的。智能指针为我们解决了资源管理的问题,让我们不再担心资源泄漏的问题。但是智能指针难道就不会存在资源泄漏的问题吗 ? 答案是NO,在用shared_ptr的时候,如果出现相互引用的情况下,shared_ptr就不能释放资源。
智能指针只是用对象去管理一个资源指针,同时用一个计数器计算当前指针引用对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器为1,此时在销毁指针管理对象的同时,也把指针管理对象所管理的指针进行delete操作。
下面是shared_ptr的程序demo。
运行结果:
从上面的代码中,可知:
1、std::make_shared封装了new方法,boost::make_shared之前的原则是既然释放资源delete由智能指针负责,那么应该把new封装起来,否则会让人觉得自己调用了new,但没有调用delete,似乎与谁申请,谁释放的原则不符。C++也沿用了这一做法。
2、随着引用对象的增加std::shared_ptr p2 = p1,指针的引用计数有1变为2,当p2退出作用域后,p1的引用计数变回1,当main函数退出后,p1离开main函数的作用域,此时p1被销毁,当p1销毁时,检测到引用计数已经为1,就会在p1的析构函数中调用delete之前std::make_shared创建的指针。
下面展示shared_ptr相互引用会导致什么样的后果 ?
先看示例代码:
运行结果如下:
只看到TestA和TestB的构造函数被调用了,没看到析构函数被调用。在main即将退出之时,ptr_a和ptr_b的引用计数都是2,因此析构函数不会被调用。智能指针ptr_a中引用了ptr_b,同样ptr_b中也引用了ptr_a,在main函数退出前,ptr_a和ptr_b的引用计数均为2,退出main函数后,引用计数均变为1,也就是相互引用。
ptr_a对ptr_b说,哎,我说ptr_b,我现在的条件是,你先释放我,我才能释放你,这是天生的,造物者决定的,改不了。ptr_b也对ptr_a说,我的条件也是一样,你先释放我,我才能释放你,怎么办?是吧,大家都没错,相互引用导致的问题就是释放条件的冲突,最终也可能导致内存泄漏。该怎么办呢 ?
此时weak_ptr就该上场了。weak_ptr相互引用不会导致引用计数增加。
把成员变量改成weak_ptr类型的,main函数不用变,那让我们再看看运行结果。
由以上代码运行结果我们可以看到:
1、所有的对象最后都能正常释放,不会存在上一个例子中的内存没有释放的问题。
2、ptr_a 和ptr_b在main函数中退出前,引用计数均为1,也就是说,在TestA和TestB中对std::weak_ptr的相互引用,不会导致计数的增加。
智能指针只是用对象去管理一个资源指针,同时用一个计数器计算当前指针引用对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器为1,此时在销毁指针管理对象的同时,也把指针管理对象所管理的指针进行delete操作。
下面是shared_ptr的程序demo。
#include <memory> class Person { public: Person() { cout << "Person default constructor" << endl; } ~Person() { std::cout << "~Person destructor" << endl; } }; int main(int argc, char** argv) { shared_ptr<Person> p1 = make_shared<Person>(); cout << "p 1 ref count:" << p1.use_count() << endl; { std::shared_ptr<Person> p2 = p1; std::cout << "p 2 ref count:" << p1.use_count() << std::endl; } std::cout << "p 3 ref count:" << p1.use_count() << std::endl; return 0; }
运行结果:
从上面的代码中,可知:
1、std::make_shared封装了new方法,boost::make_shared之前的原则是既然释放资源delete由智能指针负责,那么应该把new封装起来,否则会让人觉得自己调用了new,但没有调用delete,似乎与谁申请,谁释放的原则不符。C++也沿用了这一做法。
2、随着引用对象的增加std::shared_ptr p2 = p1,指针的引用计数有1变为2,当p2退出作用域后,p1的引用计数变回1,当main函数退出后,p1离开main函数的作用域,此时p1被销毁,当p1销毁时,检测到引用计数已经为1,就会在p1的析构函数中调用delete之前std::make_shared创建的指针。
下面展示shared_ptr相互引用会导致什么样的后果 ?
先看示例代码:
class TestB; class TestA { public: TestA() { std::cout << "TestA()" << std::endl; } void ReferTestB(std::shared_ptr<TestB> test_ptr) { m_TestB_Ptr = test_ptr; } ~TestA() { std::cout << "~TestA()" << std::endl; } private: std::shared_ptr<TestB> m_TestB_Ptr; //TestB的智能指针 }; class TestB { public: TestB() { std::cout << "TestB()" << std::endl; } void ReferTestB(std::shared_ptr<TestA> test_ptr) { m_TestA_Ptr = test_ptr; } ~TestB() { std::cout << "~TestB()" << std::endl; } std::shared_ptr<TestA> m_TestA_Ptr; //TestA的智能指针 }; int main(int argc, char** argv) { shared_ptr<TestA> ptr_a = make_shared<TestA>(); shared_ptr<TestB> ptr_b = make_shared<TestB>(); ptr_a->ReferTestB(ptr_b); ptr_b->ReferTestB(ptr_a); return 0; }
运行结果如下:
只看到TestA和TestB的构造函数被调用了,没看到析构函数被调用。在main即将退出之时,ptr_a和ptr_b的引用计数都是2,因此析构函数不会被调用。智能指针ptr_a中引用了ptr_b,同样ptr_b中也引用了ptr_a,在main函数退出前,ptr_a和ptr_b的引用计数均为2,退出main函数后,引用计数均变为1,也就是相互引用。
ptr_a对ptr_b说,哎,我说ptr_b,我现在的条件是,你先释放我,我才能释放你,这是天生的,造物者决定的,改不了。ptr_b也对ptr_a说,我的条件也是一样,你先释放我,我才能释放你,怎么办?是吧,大家都没错,相互引用导致的问题就是释放条件的冲突,最终也可能导致内存泄漏。该怎么办呢 ?
此时weak_ptr就该上场了。weak_ptr相互引用不会导致引用计数增加。
class TestB; class TestA { public: TestA() { std::cout << "TestA()" << std::endl; } void ReferTestB(std::shared_ptr<TestB> test_ptr) { m_TestB_Ptr = test_ptr; } ~TestA() { std::cout << "~TestA()" << std::endl; } private: weak_ptr<TestB> m_TestB_Ptr; //TestB的智能指针 }; class TestB { public: TestB() { std::cout << "TestB()" << std::endl; } void ReferTestB(std::shared_ptr<TestA> test_ptr) { m_TestA_Ptr = test_ptr; } ~TestB() { std::cout << "~TestB()" << std::endl; } weak_ptr<TestA> m_TestA_Ptr; //TestA的智能指针 };
把成员变量改成weak_ptr类型的,main函数不用变,那让我们再看看运行结果。
由以上代码运行结果我们可以看到:
1、所有的对象最后都能正常释放,不会存在上一个例子中的内存没有释放的问题。
2、ptr_a 和ptr_b在main函数中退出前,引用计数均为1,也就是说,在TestA和TestB中对std::weak_ptr的相互引用,不会导致计数的增加。
相关文章推荐
- C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)
- 【C++11新特性】 C++11智能指针之shared_ptr
- C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)
- 【C++11】新特性——共享资源的智能指针shared_ptr
- C++11新特性之智能指针
- 【C++11新特性】 C++11智能指针之shared_ptr
- C++11新特性之智能指针
- 【C++11新特性】 C++11智能指针之unique_ptr
- 20170911_C++11新特性之智能指针
- 【C++11新特性】 C++11智能指针之unique_ptr
- C++11新特性之智能指针
- C++11特性(10):智能指针与垃圾回收
- 【C++11新特性】 C++11智能指针之weak_ptr
- 【C++11新特性】 C++11智能指针之weak_ptr
- 【C++11新特性】 C++11智能指针之unique_ptr
- C++11特性 - Smart Pointers 智能指针
- 【C++11新特性】 C++11智能指针之shared_ptr
- C++11特性 - Smart Pointers 智能指针
- C++11新特性之智能指针
- (转载)【C++11新特性】 C++11智能指针之shared_ptr