Boost之智能指针

boost.smart_ptr库提供了六种智能指针,包括scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr和intrusive_ptr。为了使用smart_ptr组件,需要包含头文件<boost/smart_ptr.hpp>。

Scoped_ptr

scoped_ptr是一个很类似auto_ptr/unique_ptr的智能指针,但scoped_ptr的所有权更加严格,不能转让,一旦scoped_ptr获取了对象的管理权,我们就无法再从它那里取回来。与普通拇指针相比,它只有很少的接口,这一点使指针的使用更加安全,更容易使用同时更不容易被误用。

#include <iostream>
#include <string>
#include <boost/smart_ptr.hpp>
using namespace std;
using namespace boost;

int main()
{
    /* scoped_ptr的基本用法 */
    scoped_ptr<string> sp(new string("hello world"));
    cout << "content: " << *sp << ", length: " << sp->size() << endl;

    /* 无法对scoped_ptr进行拷贝构造 */
    //scoped_ptr<string> sp2 = sp;

    /* 在*和->之外scoped_ptr没有定义其他操作符 */
    //sp++;           //错误,scoped_ptr未定义递增操作
    //prev(sp);       //错误,scoped_ptr未定义递减操作

    return 0;
}
输出:

content: hello world, length: 11


scoped_array

scoped_array很像scoped_ptr,它包装了new[]操作符在堆上分配的动态数组,为动态数组提供了一个代理,保证可以正确地释放内存。但scoped_array的功能很有限,不能动态增长,没有边界检查,也没有迭代器支持,不能搭配STL算法。而且,我们应当避免使用new[]运算符,在需要动态数组的情况下我们应该使用std::vector。

#include <iostream>
#include <boost/smart_ptr.hpp>
using namespace std;
using namespace boost;

int main()
{
    /* scoped_array的基本用法 */
    int *arr = new int[10];
    scoped_array<int> sa(arr);
    fill_n(&sa[0], 10, 5);
    sa[1] = sa[2] + sa[3];
    for (int i = 0; i < 10; ++i)
        cout << sa[i] << " ";

    /* scoped_array不提供指针运算 */
    //sa[0] = 10;         //正确
    //*(sa + 1) = 20;     //错误

    return 0;
}
输出:

5 10 5 5 5 5 5 5 5 5

shared_ptr

shared_ptr是boost.smart_ptr库中最有价值、最重要的组成部分,它被毫无悬念地收入了C++11标准。shared_ptr实现的是引用计数型指针,可以被自由地拷贝和赋值,在任意的地方共享它,当引用计数为0时它才删除被包装的动态分配的对象。
基本用法
#include <iostream>
#include <boost/smart_ptr.hpp>
using namespace boost;
using std::cout;
using std::endl;

int main()
{
    shared_ptr<int> sp(new int);
    *sp = 10;

    shared_ptr<int> sp2 = sp;

    if (!sp.unique())
        cout << "sp不是指针的唯一的持有者\n";
    cout << "引用计数为" << sp.use_count() << endl;

    sp2.reset();                //将引用计数减一
    if (sp.unique())
        cout << "现在sp是指针的唯一的持有者\n";

    return 0;
}
输出:
sp不是指针的唯一的持有者
引用计数为2
现在sp是指针的唯一的持有者

工厂函数
smart_ptr库提供了一个工厂函数make_shared()来消除显示的new调用,声明如下:
template< class T, class... Args > typename boost::detail::sp_if_not_array< T >::type make_shared( Args && ... args );
通常make_shared()函数要比直接创建shared_ptr对象的方式快且高效,因为它内部仅分配一次内存,消除了shared_ptr构造时的开销。
例如:
auto sp = make_shared<string>("make_shared");
应用于标准容器
可以将shared_ptr作为容器的元素,如vector<shared_ptr<T>>,因为shared_ptr支持拷贝语义和比较操作,符合标准容器对元素的要求,所以可以在容器中安全地容纳元素的指针而不是拷贝。标准容器不能容纳scoped_ptr,因为scoped_ptr不能拷贝和赋值。
#include <iostream>
#include <vector>
#include <boost/smart_ptr.hpp>
using namespace boost;
using std::cout;
using std::endl;
using std::vector;

int main()
{
    typedef vector<shared_ptr<int>> vs;
    vs v(10);

    int i = 0;
    for (auto pos = v.begin(); pos != v.end(); ++pos) {
        (*pos) = make_shared<int>(++i);
        cout << *(*pos) << ", ";
    }
    cout << endl;

    shared_ptr<int> p = v[9];
    *p = 100;
    cout << *v[9] << endl;

    return 0;
}
输出:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
100

定制删除器
shared_ptr有这样的一个构造函数:share_ptr(Y * p, D d)。它的第一参数是要被管理的指针,它的含义与其他构造函数的参数相同。而第二个删除器参数d则告诉shared_ptr在析构时不是使用delete来操作指针p,而要用d来操作,即把delete p换成d(p)。
在这里删除器d可以是一个函数对象,也可以是一个函数指针,只要它能够像函数那样被调用,使得d(p)成立即可。对删除器的要求是它必须可拷贝,行为必须也像delete那样,不能抛出异常.
假设我们有一组操作socket的函数,使用一个socket_t类:
class socket_t {...};

socket_t *open_socket()
{
cout << "open_socket" << endl;
return new socket_t;
}

void close_socket(socket_t *s)
{
cout << "close_socket" << endl;
...
}
那么,socket资源对应的释放操作就是函数close_socket(),它符合shared_ptr对删除器的定义,可以用shared_ptr这样管理socket资源:
socket_t *s = open_socket();
shared_ptr<socket_t> p(s, close_socket); //传入删除器


shared_array

shared_array类似shared_ptr,它包装了new[]操作符在堆上分配的动态数组,它就像是shared_ptr和scoped_array的结合体,既具有shared_ptr的优点,也具有scoped_array的缺点。
#include <iostream>
#include <boost/smart_ptr.hpp>
using namespace boost;

int main()
{
    int *p = new int[10];
    shared_array<int> sa(p);
    if (sa.unique())
        std::cout << "sa唯一持有指针\n";

    shared_array<int> sa2 = sa;
    std::cout << "现在,引用计数为" << sa.use_count() << std::endl;

    sa[0] = 10;
    std::cout << "sa2[0] = " << sa2[0];

    return 0;
}
输出:
sa唯一持有指针
现在,引用计数为2
sa2[0] = 10


weak_ptr

weak_ptr是为配合shared_ptr而引入的一种智能指针,它更像是sharead_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->。它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,把弱关系转换为强关系
#include <iostream>
#include <vector>
#include <boost/smart_ptr.hpp>
using namespace boost;
using std::cout;
using std::endl;

int main()
{
    shared_ptr<int> sp(new int[10]);
    weak_ptr<int> wp(sp);
    cout << "引用计数:" << wp.use_count() << endl;          //weak_ptr不影响引用计数

    if (!wp.expired()) {        //相当于wp.use_count() == 1
        shared_ptr<int> sp2 = wp.lock();
        cout << "现在,引用计数为" << wp.use_count() << endl;
    }

    sp.reset();                 //shared_ptr失效
    cout << "引用计数为" << wp.use_count() << endl;

    return 0;
}
输出:
引用计数:1
现在,引用计数为2
引用计数为0

intrusive_ptr

intrusive_ptr也是引用计数型指针,所以它的接口与shared_ptr很像,但它自己不直接管理引用计数,而是调用下面两个函数来间接管理:
void intrusive_ptr_add_ref(T * p); //增加引用计数
void intrusive_ptr_release(T * p); //减少引用计数
intrusive_ptr的构造函数和reset()还多出一个add_ref参数,表示是否增加引用计数,如果add_ref==true,那么它就相当于weak_ptr,只是简单地观察对象。
#include <iostream>
#include <vector>
#include <boost/smart_ptr.hpp>
using namespace boost;
using std::cout;
using std::endl;

struct counted_data
{
    // ...
    int m_count = 0;
    ~counted_data()
    {
        cout << "dtor" << endl;
    }
};

void intrusive_ptr_add_ref(counted_data* p)
{
    ++p->m_count;
}

void intrusive_ptr_release(counted_data* p)
{
    if(--p->m_count == 0)
        delete p;
}

int main()
{
    typedef intrusive_ptr<counted_data> counted_ptr;

    counted_ptr p(new counted_data);
    cout << p->m_count << endl;         // 1

    counted_ptr p2(p);
    cout << p2->m_count << endl;        // 2

    counted_ptr weak_p(p.get(), false);
    cout << weak_p->m_count << endl;    // 2

    p2.reset();
    cout << p->m_count << endl;         // 1

    return 0;
}
输出:
1
2
2
1
dtor


为了简化实现引用计数的工作,intrusive_ptr在头文件<boost/smart_ptr/intrusive_ref_counter.hpp>里定义了一个辅助类intrusive_ref_counter,它需要被继承使用,这样子类就会自动获取引用计数的能力。
#include <iostream>
#include <boost/smart_ptr.hpp>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
using namespace boost;
using std::cout;
using std::endl;

struct counted_data2 : public intrusive_ref_counter<counted_data2>
{
    ~counted_data2()
    {
        cout << "dtor2" << endl;
    }
};

int main()
{
    typedef intrusive_ptr<counted_data2> counted_ptr;

    counted_ptr p(new counted_data2);
    cout << p->use_count() << endl;

    return 0;
}
输出:
1
dtor
2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值