boost智能指针

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()
原文地址:https://www.cnblogs.com/aizh/p/15749853.html