c++11 boost - smart_ptr 库 - 智能指针

2018-07-10 19:04:34

如果对象实在栈上动态内存创建的,那么一旦离开作用域,对象会销毁资源也同时会释放。但是如果是使用 new 创建的,则必须显式调用 delete 来释放。

C++引入异常机制后,如果没有智能指针,程序员必须保证new对象能在正确的时机delete,必须到处编写异常捕获代码以释放资源,而智能指针则可以在退出作用域时 - 不管是正常流程离开或是因异常离开 - 总调用delete来析构在堆上动态分配的对象。

auto_ptr 是 c++98 标准的智能指针,在 c++11已废弃。

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

scoped_ptr 类似 unique_ptr,但是它很严格,只能在自己的作用域里,所有权不能转让。

template<class T> class scoped_ptr {
  private:

    scoped_ptr(scoped_ptr const&);         //拷贝构造函数私有化
    scoped_ptr& operator=(scoped_ptr const&); //赋值操作私有化

    void operator==(scoped_ptr const&) const; //相等操作私有化
    void operator!=(scoped_ptr const&) const; //不等操作私有化

  public:

    typedef T element_type;

    explicit scoped_ptr(T * p = 0) noexcept;  //显式构造函数
    ~scoped_ptr() noexcept;  //析构函数

    void reset(T * p = 0) noexcept;  //重置智能指针

    //下面运算符重载为了模拟现实的指针操作
    T & operator*() const noexcept;
    T * operator->() const noexcept;

    T * get() const noexcept;   //返回原始指针,比如底层的C接口要用

    explicit operator bool() const noexcept;  //显式boo值转型

    void swap(scoped_ptr & b) noexcept;  //交换指针
  };

unique_ptr 是c++11标准定义的新的智能指针,用来取代 auto_ptr。相较于scoped_ptr有更多的功能。可以定制删除器,可以安全放入标准容器。

例子

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

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

void case1()
{
    scoped_ptr<string> sp(new string("text"));

    assert(sp);
    assert(sp != nullptr);
	
	//可以跟正常指针一样使用
    cout << *sp << endl;
    cout <<  sp->size() << endl;
}

struct posix_file
{
    posix_file(const char * file_name)
    {   cout << "open file:" << file_name << endl; }
    ~posix_file()
    {   cout << "close file" << endl;   }
};

void case2()
{
    scoped_ptr<posix_file> fp(new posix_file("/tmp/a.txt"));

    scoped_ptr<int> p(new int);

    if (p)
    {
        *p = 100;
        cout << *p << endl;
    }

    p.reset();

    assert(p == 0);
    if (!p)
    {   cout << "scoped_ptr == nullptr" << endl;   }

}

//////////////////////////////////////////

class ptr_owned final
{
    scoped_ptr<int> m_ptr;
};


void bad_case()
{
    scoped_ptr<string> sp(new string("text"));

    //sp++;  未定义递增
    //scoped_ptr<string> sp2 = sp;
    //std::prev(sp);  未定义递减
    //ptr_owned p;
    //ptr_owned p2(p);  不允许拷贝构造
}

void case_unique()
{
    auto p = boost::make_unique<int>(10);

    assert(p && *p == 10);
    
    //释放指针控制,此时必须手动释放内存
    int *dd = p.release();
    assert(!p);
    delete dd;
    
    
    auto a = boost::make_unique<int[]>(5);
    a[0] = 100;
    a[4] = 500;
    //a[5] = 1000;
}

int main()
{
    case1();
    case2();
    case_unique();
}
[root@192 c++]# g++ -std=c++11 main.cpp 
[root@192 c++]# ./a.out 
text
4
open file:/tmp/a.txt
100
scoped_ptr == nullptr
close file


shared_ptr 内置了引用计数,当引用计数为0时才会释放内存。shared_ptr 提供了最基本的线程安全保证。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
#include <exception>
#include <map>

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

//////////////////////////////////////////

void case1()
{
    shared_ptr<int> spi(new int);
    assert(spi);
    *spi = 253;

    shared_ptr<std::string>  sps(new std::string("smart"));
    assert(sps->size() == 5);

    //shared_ptr<int> dont_do_this(new int[10]);
}

//////////////////////////////////////////

void case2()
{
    typedef shared_ptr<std::string> sp_t;
    std::map<sp_t, int> m;

    sp_t sp(new std::string("one"));
    m[sp] = 111;

    shared_ptr<std::exception> sp1(new std::bad_exception());

    //下面的指针转换是 shared_ptr 特有的
    //向下转型为 std::bad_exception 指针
    auto sp2 = dynamic_pointer_cast<std::bad_exception>(sp1);

    //可以转回来
    auto sp3 = static_pointer_cast<std::exception>(sp2);
    assert(sp3 == sp1);
}

//////////////////////////////////////////

void case3()
{
    shared_ptr<int> sp(new int(10));
    assert(sp.unique()); //是否唯一

    shared_ptr<int> sp2 = sp;
	
    assert(sp == sp2 &&
     sp.use_count() == 2);

    *sp2 = 100;
    assert(*sp == 100);
	
	std::cout << sp.unique() << std::endl;
	
    sp.reset();
    assert(!sp);
}

//////////////////////////////////////////

class shared
{
private:
    shared_ptr<int> p;
public:
    shared(shared_ptr<int> p_):p(p_){}
    void print()
    {
        std::cout << "count:" << p.use_count()
            << " v=" <<*p << std::endl;
    }
};

void print_func(shared_ptr<int> p)
{
    std::cout << "count:" << p.use_count()
        << " v=" <<*p << std::endl;
}

void case4()
{
    shared_ptr<int> p(new int(100));
    shared s1(p), s2(p);

    s1.print();
    s2.print();

    *p = 20;
    //传递为函数参数,引用计数为加1
    print_func(p);

    s1.print();
}

//////////////////////////////////////////

void case5()
{
    auto sp = make_shared<std::string>("make_shared");
    auto spv = make_shared<std::vector<int> >(10, 2);
    assert(spv->size() == 10);
}

//////////////////////////////////////////

void case6()
{
    typedef std::vector<shared_ptr<int> > vs;
    
    //元素被初始化为10个空指针
    vs v(10);

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

	//c++新式for循环
    for (auto& ptr : v)
    {
        ptr = make_shared<int>(++i);
        std::cout << *ptr << ", ";
    }
    std::cout << std::endl;

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

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
}
[root@192 c++]# g++ -std=c++11  main.cpp 
[root@192 c++]# ./a.out 
0
count:3 v=100
count:3 v=100
count:4 v=20
count:3 v=20
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
100
// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
#include <set>

#include <boost/core/ignore_unused.hpp>
#include <boost/smart_ptr.hpp>
using namespace boost;

//////////////////////////////////////////

//桥接模式
class sample
{
private:
    class impl;   //不完整的内部类
    shared_ptr<impl> p;
public:
    sample();
    void print();  //提供给外部的接口
};

class sample::impl
{
public:
    void print()
    {   std::cout << "impl print" << std::endl;}
};

//构造函数初始化 shared_ptr
sample::sample():p(new impl){}

void sample::print()
{   p->print();}

void case1()
{
    sample s;
    s.print();
}

//假设你为类定义了构造函数,那么类就不会自动提供默认的构造函数了
//然而,如果你仍然想使用类提供的默认版本,那么可以使用default关键字

//工厂模式
class abstract
{
public:
    virtual void f() = 0;  //纯虚函数
    virtual void g() = 0;
protected:
	//除了自己和子类,其他无权调用 delete
    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 shared_ptr<abstract>(new impl);}
{   return make_shared<impl>();}

void case2()
{
    auto p = create();
    p->f();
    p->g();

    abstract *q = p.get();
    boost::ignore_unused(q);
    //delete q;
}

//////////////////////////////////////////

class socket_t {};

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

void close_socket(socket_t * s)
{
    std::cout << "close_socket" << std::endl;
}

//定制删除器,作用很大,用户可以自定义复杂的释放资源
void case3()
{
    socket_t *s = open_socket();
    
    //在析构的时候不调用 delete
    //而是调用 close_socket(s)
    shared_ptr<socket_t> p(s, close_socket);
    //shared_ptr<socket_t> p(s, &close_socket);等价
}

//////////////////////////////////////////

bool case4()
{
    auto p = make_shared<int>(776);

    assert(p);
    if(p)
    {
        std::cout << "explicit cast" << std::endl;
    }
	
    //return !!p;
    return static_cast<bool>(p);
    
}


void any_func(void* p)
{   std::cout << "some operate" << std::endl;}

void case5()
{
	//删除器的高级功能
	//定制空指针,退出作用域就能执行我们想要
	//执行的 any_func
    shared_ptr<void> p(nullptr,any_func);
}

//////////////////////////////////////////

void case6()
{
    auto p1 = make_shared<std::pair<int, int>>(0,1); //一个pair只能指针

    shared_ptr<int> p2(p1, &p1->second); //别名构造

    assert(p1.use_count() == 2 &&
           p1.use_count() == p2.use_count()); //计数相同
    assert((void*)p1.get() != (void*)p2.get()); //指向的内容不同
    assert(&p1->second== p2.get());  //指向的是另外的指针。
}

//////////////////////////////////////////
#include <boost/smart_ptr/owner_less.hpp>

void case7()
{
    typedef shared_ptr<int> int_ptr;
    typedef owner_less<int_ptr> int_ptr_less;

    int_ptr p1(new int(10));
    int n = 20;
    int_ptr p2(p1, &n);

    assert(!int_ptr_less()(p1, p2) &&
           !int_ptr_less()(p2, p1));

    typedef std::set<int_ptr> int_set;

    int_set s;
    s.insert(p1);
    s.insert(p2);
    assert(s.size() == 1);
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
}
[root@192 c++]# g++ -std=c++11  main.cpp 
[root@192 c++]# ./a.out 
impl print
class impl f
class impl g
open_socket
close_socket
explicit cast
some operate

weak_ptr 是用来协助 shared_ptr的,作为旁观者。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
//using namespace std;

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

//////////////////////////////////////////

void case1()
{
    shared_ptr<int> sp(new int(10));
    assert(sp.use_count() == 1);

    weak_ptr<int> wp(sp);
    assert(wp.use_count() == 1);

    if (!wp.expired())
    {
        shared_ptr<int> sp2 = wp.lock(); //获得一个shared_ptr,引用计数+1
        *sp2 = 100;
        assert(wp.use_count() == 2);
    }

    assert(wp.use_count() == 1);
    sp.reset();
    assert(wp.expired());  //引用计数为0
    assert(!wp.lock());
}

//////////////////////////////////////////

class self_shared:
    public enable_shared_from_this<self_shared>
{
public:
    self_shared(int n):x(n){}
    int x;
    void print()
    {   std::cout << "self_shared:" << x << std::endl;    }
};

void case2()
{
    auto sp = make_shared<self_shared>(313);
    sp->print();

    auto p = sp->shared_from_this();
    auto p1 = sp->shared_from_this();

	std::cout << sp.use_count() << std::endl;

    p->x = 1000;
    p->print();
}

//利用weak_ptr 来解决 shared_ptr 循环引用导致
//引用计数永远不为0的问题
class node
{
public:
    ~node()
    {     std::cout << "deleted" << std::endl;}

    typedef weak_ptr<node> ptr_type;
    //typedef shared_ptr<node> ptr_type;
    ptr_type next;
};

void case3()
{
    auto p1 = make_shared<node>();
    auto p2 = make_shared<node>();

    p1->next = p2;
    p2->next = p1;

    assert(p1.use_count() == 1);
    assert(p2.use_count() == 1);

    if(!p1->next.expired())
    {
        auto p3 = p1->next.lock();
    }
}

//////////////////////////////////////////
#include <boost/smart_ptr/enable_shared_from_raw.hpp>

class raw_shared:
    public enable_shared_from_raw
{
public:
    raw_shared()
    {   std::cout << "raw_shared ctor" << std::endl;    }
    ~raw_shared()
    {   std::cout << "raw_shared dtor" << std::endl;    }
};

void case4()
{
    raw_shared x;
    assert(weak_from_raw(&x).use_count() == 1);
    auto px = shared_from_raw(&x);
    assert(px.use_count() == 2);

    auto p = new raw_shared;

    auto wp = weak_from_raw(p);
    assert(wp.use_count() == 1);

    decltype(shared_from_raw(p)) spx(p);

    auto sp = shared_from_raw(p);
    //std::cout << sp.use_count() << std::endl;
    assert(sp.use_count() == 2);

    //decltype(sp) spx(p);

    auto sp2 = sp;
    auto wp2 = weak_from_raw(p);
    assert(wp2.use_count() == 3);
}


//////////////////////////////////////////

int main()
{
    case1();
    case2();
    case3();
    case4();
}
[root@192 c++]# ./a.out 
self_shared:313
3
self_shared:1000
deleted
deleted
raw_shared ctor
raw_shared ctor
raw_shared dtor
raw_shared dtor


 备注

1.编译器版本gcc4.8.5,运行环境centos7 64位
2.本文只做简单记录用,详细用法请参考 Boost Library,或者是罗剑锋的 boost程序库完全开发指南 书本
3..原文地址http://www.freecls.com/a/2712/9d


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。