boost提供的智能指针都是轻量级的对象,速度与原始指针相差无几,都是异常安全的,对于所指向的类型也仅由一个要求:指向的类型T的析构函数不能抛出异常。
一、scoped_ptr
此智能指针包装了 new 操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。
当 scoped_ptr 对象的生命周期结束时,析构函数会使用 delete 操作符自动销毁所管理的对象,从而正确地回收资源。
其特点是不能转让,一旦获取了对象的管理权,就无法再从它那里取回来。因为它将拷贝构造函数和赋值操作符都声明为私有的,禁止对智能指针的拷贝操作。这也说明了如果一个类持有 scoped_ptr 成员变量,那么它也是不可拷贝和赋值的。
scoped_ptr 不能用于容器,因为它不能拷贝和赋值。
#include <boost/smart_ptr.hpp>
using namespace boost;
class test
{
public:
test(int value):value(value)
{
}
void showValue()
{
qDebug()<<value;
}
~test()
{
qDebug()<<"析构test value = "<<value;
}
private:
int value;
};
int main()
{
scoped_ptr<test> sp(new test(666));
//delete sp;//错误,因为sp不是一个指针
if(sp) //转为bool
qDebug()<<"sp非空";
sp.reset(new test(888));//重置
test * p = sp.get();//获取原始指针
p->showValue();
sp->showValue();
}
二、shared_ptr
是boost最重要的智能指针,被添加到标准库了。
与 scoped_ptr 一样包装了 new 操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针,可以被自由地拷贝和赋值,在任意的地方共享它,当引用计数为0时才删除被包装的动态分配的对象。
shared_ptr 也可以安全地放到标准容器中,是在STL容器中存储指针的最标准解法。
2.1、工厂函数
一般地,new 创建出来的对象要 delete 销毁掉,智能指针消除了 delete 调用,如果使用者对对象只需要 new 不需要 delete 感到别扭,可以使用工厂函数创建对象,工厂函数消除了 new 的调用。
int main()
{
auto sp = make_shared<test>(999);
sp->showValue();
}
2.2、shared_ptr 用于容器的两种方式
int main()
{
QList<shared_ptr<test>> list;
list.append(make_shared<test>(111));
list.append(make_shared<test>(222));
list.first()->showValue();
shared_ptr<QList<test*>> list2 = make_shared<QList<test*>>();
list2->append(new test(444));
list2->append(new test(555));
list2->first()->showValue();
qDeleteAll(*list2.get());
}
第二种还要手动释放,推荐使用第一种。
2.3、示例:shared_ptr 用于工厂方法
class abstract
{
public:
virtual void f() = 0;
virtual void g() = 0;
protected:
virtual ~abstract() = default;
};
class impl:public abstract
{
public:
impl() = default;
virtual ~impl() = default;
public:
virtual void f()
{ std::cout << "class impl f" << std::endl; }
virtual void g()
{ std::cout << "class impl g" << std::endl; }
};
shared_ptr<abstract> create()
{ return make_shared<impl>();}
void main()
{
auto p = create();
p->f();
p->g();
abstract *q = p.get();
//delete q; //错误,abstract的析构函数是protected的,除了它自己和它的子类,其他对象无权调用delete删除它
//除非强转为 impl 类型,然后delete(不建议的操作)
}
这里使用创建对象返回的是智能指针,避免了忘了 delete 导致内存泄漏的隐患。
2.4、定制删除器
shared_ptr 构造时可以传入一个函数作为删除器,它将在对象被删除时调用。
void deleter(test * t)
{
qDebug()<<"调用删除器 ";
t->showValue();
}
int main()
{
shared_ptr<test> sp(new test(888),&deleter);
// auto sp2 = make_shared<test>(999,&deleter);//不可用
}
2.5、shared_ptr<void>
shared_ptr<void> 能够存储 void* 型的指针,而 void* 型指针可以指向任意类型,因此 shared_ptr<void> 就像是一个泛型的指针容器,拥有容纳任意类型的能力。
但将指针存储为 void* 同时也丧失了原来的类型信息,为了在需要的时候正确使用,可以用转型函数重新转为原来的指针。但这涉及运行时动态类型转换,会使代码不够安全,建议最好不要这样使用。
2.6、转换类型函数
int main()
{
shared_ptr<void> vp = make_shared<test>(666);
shared_ptr<test> sp = static_pointer_cast<test>(vp);
shared_ptr<test> sp2 = const_pointer_cast<test>(vp);
shared_ptr<test> sp3 = dynamic_pointer_cast<test>(vp);
//错误的:
// shared_ptr<test> sp2 = static_cast<test>(vp);
// shared_ptr<test> sp3 = static_cast<shared_ptr<test>>(vp);
}
2.7、删除器的高级用法
实现在vp析构时调用任何函数:
void any_func(void *)
{
qDebug()<<"任何操作";
}
int main()
{
shared_ptr<void> vp(nullptr,&any_func);
}