1.关于智能指针
智能指针是存储“指向动态分类(在堆上)的对象的指针”。类似与普通指针,不同的是它们会在适当的时间自动回收空间。智能指针在面对出现异常情况下有着较好的下效果,可以确保动态分配的对象被析构。
2.scoped_ptr
- scoped_ptr存储一个指向动态分配对象的指针,在scoped_ptr析构过程中,或者reset,需要保证它所指的对象被删除;
- scoped_ptr实际上是对裸指针的包装,但是限制了指针的复制行为;
- 和std::auto_ptr类似,但没有所有权的转移的行为;
- scoped_ptr不能复制,所以不能当作容器元素。
#include <iostream> #include <boost/scoped_ptr.hpp> struct A{ A(){ std::cout << "A::A()" << std::endl;
} ~A(){ std::cout << "A::~A()" << std::endl; } void f(){ std::cout << "A::f()" << std::endl; } }; int main(){ boost::scoped_ptr<int> sp(new int(128)); // 建议使用 std::cout << ++(*sp) << std::endl; // Error 由于scoped_ptr将拷贝和赋值构造均设置为private,一个对象只能被一个只能指针包含 // boost::scoped_ptr<int> sp2(sp); boost::scoped_ptr<A> ap(new A); // 建议使用 ap->f(); std::cout << " --------------- " << std::endl; // 由于对象a是栈上的对象,会自行析构,若在采用智能指针指向,会两次析构 // A a; // boost::scoped_ptr<A> ap2(&a); // Error free(): invalid pointer // 可以这样作,但是尽量不要,由于A对象的指针a暴露在外面,会可能产生其他操作,导致问题出现 A* a = new A; boost::scoped_ptr<A> ap2(a); }
// 输出
129
A::A()
A::f()
---------------
A::A()
A::~A()
A::~A()
3.shared_ptr
shared_ptr可以多个智能指针管理同一个对象,并通过计数统计有多少个智能指针管理该对象,只有当计数为0时,所指对象指针会被析构。
由于可以复制,因此shared_ptr可以和标准库中容器一起工作
#include <iostream> #include <boost/shared_ptr.hpp> struct A{ A(){ std::cout << "A::A()" << std::endl; } ~A(){ std::cout << "A::~A()" << std::endl; } void f(){ std::cout << "A::f()" << std::endl; } }; int main(){ boost::shared_ptr<int> sp(new int(128)); // 建议使用 std::cout << ++(*sp) << std::endl; boost::shared_ptr<int> sp2(sp); std::cout << sp2.use_count() << std::endl; // 引用计数 boost::shared_ptr<A> ap(new A); // 建议使用 ap->f(); std::cout << " --------------- " << std::endl; }
// 输出
129
2
A::A()
A::f()
---------------
A::~A()
4.make_shared
使用shared_ptr可以消除对显示delete的使用,但是没有避免现实new的支持,必须通过如下等方式构建:
boost::shared_ptr<A> ap(new A);
因此,通过make_shared()解决这个问题。
头文件<boost/make_shared.hpp>提供了一组重载函数模板,make_shared使用operator new来分配内存。
#include <iostream> #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <string> using namespace std; class Cls1{ public: Cls1(){ cout << "Cls1()" << endl; } Cls1(int age,string name):_age(age),_name(name){ cout << "Cls1(int age,string name)" << endl; } ~Cls1(){ cout << "~Cls1()" << endl; } private: int _age; string _name; }; class Cls2{ public: Cls2(){ cout << "Cls2()" << endl; } Cls2(int age):_age(age){ cout << "Cls2(int age)" << endl; } ~Cls2(){ cout << "~Cls2()" << endl; } private: int _age; }; int main(){ // 调用Cls1的无参构造 boost::shared_ptr<Cls1> clp = boost::make_shared<Cls1>(); // 调用Cls1的带有两个构造 boost::shared_ptr<Cls1> clp1 = boost::make_shared<Cls1>(10,"ai"); // 调用Cls2的带有一个构造 boost::shared_ptr<Cls2> clp2 = boost::make_shared<Cls2>(10); return 0; }
5.shared_ptr循环引用问题
#include <iostream> #include <boost/shared_ptr.hpp> using namespace std; class B; class A{ public: A(){ cout << "A()" << endl; } ~A(){ cout << "~A()" << endl; } boost::shared_ptr<B> pb; }; class B{ public: B(){ cout << "B()" << endl; } ~B(){ cout << "~B()" << endl; } boost::shared_ptr<A> pa; }; int main(){ boost::shared_ptr<A> a(new A); boost::shared_ptr<B> b(new B); a->pb = b; b->pa = a; cout << a.use_count() << endl; cout << b.use_count() << endl; cout << "---------------" << endl; return 0; }
//输出
A::A()
B()
2
2
--------------
从上述结果可以看出,最后new出来的A和B的对象均没有被析构。是由于a的成员变量是b,b的成员变量是a,导致两个智能指针的引用计数均为2,都等着对方结束,从而产生类似“死锁”的问题。因此,后续通过weak_ptr可以解决上述问题。
6.通过weak_ptr解决shared_ptr循环引用
weak_ptr类模板存储一个引向被shared_ptr管理的对象的若引用,weak_ptr管理对象之后不会增加它的引用计数,由于weak_ptr没有重载->,*等操作符。因此不能直接操作它所管理的对象,则必须通过lock函数将weak_ptr转化为shared_ptr。同样地,weak_ptr也可以和标准库中的容器一起工作。
#include <iostream> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> struct A{ A(){ std::cout << "A::A()" << std::endl; } ~A(){ std::cout << "A::~A()" << std::endl; } void f(){ std::cout << "A::f()" << std::endl; } }; int main(){ boost::shared_ptr<int> sp(new int(128)); // 建议使用 std::cout << ++(*sp) << std::endl; boost::shared_ptr<int> sp2(sp); std::cout << sp2.use_count() << std::endl; // 引用计数 boost::weak_ptr<int> wp(sp2); std::cout << wp.use_count() << std::endl; // 2 weak_ptr弱引用,不占计数次数 std::cout << *wp.lock() << std::endl; // lock() 将weak_ptr转换为shared_ptr boost::shared_ptr<A> ap(new A); // 建议使用 ap->f(); std::cout << " --------------- " << std::endl; return 0; }
//输出
129
2
2 // 2 weak_ptr弱引用,不占计数次数
129
A::A()
A::f()
---------------
A::~A()
由于weak_ptr不占引用计数,因此对于(5)产生的引用计数问题,则可以直接将class A中boost::shared_ptr<B> pb改为boost::weak_ptr<B> pb;则便可以完全析构。
class A{
public:
A(){
cout << "A()" << endl;
}
~A(){
cout << "~A()" << endl;
}
//boost::shared_ptr<B> pb;
boost::weak_ptr<B> pb;
};
7.pimpl(private implemets)
pimpl主要是为了隐藏类定义细节的一种手法。
// 头文件 Example.h #ifndef EXAMPLE_H_ #define EXAMPLE_H_ #include <boost/shared_ptr.hpp> class Example { public: Example(); Example(int x); int get_i(); private: // int i; // 隐藏变量i class implementation; boost::shared_ptr<implementation> _imp; }; #endif /* EXAMPLE_H_ */
// 实现文件 Example.cpp
#include <iostream> #include "Example.h" class Example::implementation{ // 对类进行实现 public: int i; implementation(){ } ~implementation(){ std::cout << "~implementation()" << std::endl; } }; Example::Example():_imp(new implementation){ } Example::Example(int x): _imp(new implementation){ _imp->i = x; } int Example::get_i(){ return _imp->i; }
// 测试文件 piplm_test.cpp #include <iostream> #include "Example.h" int main(){ Example e(10); std::cout << e.get_i() << std::endl; return 0; }
// 输出
10
~implementation()