`
dongtianzhe
  • 浏览: 21514 次
  • 性别: Icon_minigender_1
  • 来自: 长春
最近访客 更多访客>>
社区版块
存档分类
最新评论

Boost学习1-智能指针

阅读更多
智能指针的原理是基于RAII:申请资源即初始化。一个动态分配的对象由智能指针管理,在任何情况下动态分配的内存都能得到正确释放,从而将开发人员从这项任务中解放了出来。

作用域指针:

boost::scoped_ptr,一个作用域指针独占一个动态分配的对象,不能将一个作用域指针所包含的对象传递给另一个作用域指针。

一经初始化,智能指针 boost::scoped_ptr 所包含的对象,可以通过类似于普通指针的接口来访问。 这是因为重载了相关的操作符 operator*(),operator->() 和 operator bool() 。 此外,还有 get() 和 reset() 方法。 前者返回所含对象的地址,后者用一个新的对象来重新初始化智能指针。 在这种情况下,新创建的对象赋值之前会先自动释放所包含的对象。

boost::scoped_ptr 的析构函数中使用 delete 操作符来释放所包含的对象。 这对 boost::scoped_ptr 所包含的类型加上了一条重要的限制: boost::scoped_ptr 不能用动态分配的数组来做初始化,因为这需要调用 delete[] 来释放。

作用域数组:

boost::scoped_array,作用域数组的使用方式与作用域指针相似。 关键不同在于,作用域数组的析构函数使用 delete[] 操作符来释放所包含的对象。 因为该操作符只能用于数组对象,所以作用域数组必须通过动态分配的数组来初始化。

共享指针:

boost::shared_ptr,智能指针 boost::shared_ptr 基本上类似于 boost::scoped_ptr。 关键不同之处在于 boost::shared_ptr 不一定要独占一个对象。 它可以和其他 boost::shared_ptr 类型的智能指针共享所有权。 在这种情况下,当引用对象的最后一个智能指针销毁后,对象才会被释放。

shared_ptr相对于标准库中auto_ptr来说,有一项重要的改进,可以再容器中存放shared_ptr对象。但是你不能在标准容器中存储 std::auto_ptr,因为它们在拷贝的时候传递了所有权。
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <vector>

using namespace std;

int main()
{
    typedef vector< boost::shared_ptr<int> > ShareV;
    ShareV v1;
    v1.push_back(boost::shared_ptr<int>(new int(1)));
    v1.push_back(boost::shared_ptr<int>(new int(2)));

    for (ShareV::const_iterator it = v1.begin(); it != v1.end(); ++it) {
        cout << **it << endl;
    }
    return 0;
}


共享数组:

boost::shared_array,共享数组的行为类似于共享指针。 关键不同在于共享数组在析构时,默认使用 delete[] 操作符来释放所含的对象。 因为这个操作符只能用于数组对象,共享数组必须通过动态分配的数组的地址来初始化。

弱指针:

boost::weak_ptr,弱指针只有在配合共享指针一起使用时才有意义。一个强引用当被引用的对象活着的话,这个引用也存在(就是说,当至少有一个强引用,那么这个对象就不能被释放)。boost::share_ptr就是强引用。

相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它存在的时候的一个引用。弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。

weak_ptr的lock函数返回一个引向weak_ptr所观察的资源的 shared_ptr ,如果可以的话。如果没有这样指针(即 weak_ptr 引向的是空指针),shared_ptr 也将引向空指针。否则,shared_ptr所引向的资源的引用计数将正常地递增。
#include <iostream>
#include <boost/weak_ptr.hpp>
#include <pthread.h>

using namespace std;


void * reset(void *arg)
{
    boost::shared_ptr<int> *sh = static_cast<boost::shared_ptr<int> *>(arg);
    sleep(1);
    sh->reset(); // 重置
}

void * print(void *arg)
{
    boost::weak_ptr<int> *w = static_cast<boost::weak_ptr<int> *>(arg);
    boost::shared_ptr<int> sh = w->lock(); // 如果已经被重置了,则返回空;如果没有被重置,则返回一个shared_ptr并且引用计数加1,这样永远都不会出错了
    if (sh)
        cout << *sh << endl;
}


int main()
{
    boost::shared_ptr<int> i(new int(4));
    boost::weak_ptr<int> w(i);

    int err = 0;
    pthread_t tid1, tid2;
    
    err = pthread_create(&tid1, NULL, reset, &i);
    if(err != 0) {
        cerr << "can't create pthread 1" << endl;
        exit(1);
    }

    err = pthread_create(&tid2, NULL, print, &w);
    if( err != 0 ) {
        cerr << "can't create pthread 2" << endl;
        exit(1);
    }

    err = pthread_join(tid1, NULL);
    if (err != 0) {
        cerr << "can't join thread 1" << endl;
        exit(1);
    }

    err = pthread_join(tid2, NULL);
    if( err != 0 ) {
        cerr << "can't join thread 2" << endl;
        exit(1);
    }

    return 0;
}


那么weak_ptr有什么用呢?一个最大的用处就是管理循环引用的对象。下面我们看一个例子:
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

class parent;
class children;

typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<children> children_ptr;

class parent
{
public:
    ~parent() { std::cout <<"destroying parent\n"; }

public:
    children_ptr children;
};

class children
{
public:
    ~children() { std::cout <<"destroying children\n"; }

public:
    parent_ptr parent;
};


void test()
{
    parent_ptr father(new parent());
    children_ptr son(new children);

    father->children = son;
    son->parent = father;
}

int main()
{
    std::cout<<"begin test...\n";
    test();
    std::cout<<"end test.\n";
    return 0;
}


注意看test函数,即使退出了test函数后,由于parent和children对象互相引用,它们的引用计数都是1,不能自动释放,并且此时这两个对象再无法访问到。这就引起了c++中那臭名昭著的内存泄漏。我们看一下内存布局图:



当test结束的时候,局部变量father和son会析构,father析构的时候,由于他持有对象的引用计数为2,所以仅仅将引用计数减1,son也一样,test函数结束后,内存布局如下图:



我们可以通过boost::weak_ptr来打破循环引用

由于弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。对于上面的那个例子来说,只要把children的定义改为如下方式,即可解除循环引用:

class children
{
public:
    ~children() { std::cout <<"destroying children\n"; }

public:
    boost::weak_ptr<parent> parent;
};


最后值得一提的是,虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅是一种编译期的解决方案,如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。因此,不要认为只要使用了智能指针便能杜绝内存泄漏。毕竟,对于C++来说,由于没有垃圾回收机制,内存泄漏对每一个程序员来说都是一个非常头痛的问题。

介入式指针:

大体上,介入式指针的工作方式和共享指针完全一样。 boost::shared_ptr 在内部记录着引用到某个对象的共享指针的数量,可是对介入式指针来说,程序员就得自己来做记录。 对于框架对象来说这就特别有用,因为它们记录着自身被引用的次数。

指针容器:
在你见过 Boost C++ 库的各种智能指针之后,应该能够编写安全的代码,来使用动态分配的对象和数组。多数时候,这些对象要存储在容器里——如上所述——使用 boost::shared_ptr 和 boost::shared_array 这就相当简单了。
然而因为某些原因,实际情况中并不这么用。 第一,反复声明 boost::shared_ptr 需要更多的输入。 其次,将 boost::shared_ptr 拷进,拷出,或者在容器内部做拷贝,需要频繁的增加或者减少内部引用计数,这肯定效率不高。 由于这些原因,Boost C++ 库提供了 指针容器 专门用来管理动态分配的对象。
boost::ptr_vector 独占它所包含的对象,因而容器之外的共享指针不能共享所有权,这跟 std::vector<boost::shared_ptr<int> > 相反。


  • 大小: 6.8 KB
  • 大小: 5.4 KB
分享到:
评论

相关推荐

    boost学习书籍汇总

    An+Introduction+to+Boost.chm Beyond+the+C+++Standard+Library(中文版).pdf Boost And STL学习资料 .chm boost graph library.pdf Boost程序库完全开发指南.pdf ...智能指针的标准之争 Boost_vs_Loki.pdf

    十多本关于Boost的书及资料,pdf+chm

    AnIntroduction+to+Boost.chm Beyond+the+C+++Standard+Library(中文版).pdf Beyond_STL An Introduction to Boost中文.chm Boost And STL学习资料 .chm boost graph library....智能指针的标准之争 Boost_vs_Loki.pdf

    C++ 中boost::share_ptr智能指针的使用方法

    最近项目中使用boost库的智能指针,感觉智能指针还是蛮强大的,在此贴出自己学习过程中编写的测试代码,以供其他想了解boost智能指针的朋友参考,有讲得不正确之处欢迎指出讨论。当然,使用boost智能指针首先要编译...

    boost_1_55_0.zip

    Boost库1.55.0版本的源码,可用以学习智能指针,stl标准容器等...,是刨析源码加以学习的最好资料。

    boost_1_69_0.tar.bz2

    boost向来有准标准库之称,很多新特性例如智能指针等都是先在boost中实现,后来被吸收到标准库之中。而且boost实现了日志、算法、日期、地理、数学、线程协程等各种实用工具,所以如果要学习C++,boost是必须要学习...

    Boost库定制安装更新版

     5个智能指针,学习智能指针必读,一份不错的参考是来自CUJ的文章:  Smart Pointers in Boost,哦,这篇文章可以查到,CUJ是提供在线浏览的。中文版见笔者在《Dr.Dobb's Journal软件研发杂志》第7辑上的译文。  ...

    The Boost C++ Libraries 中文版.zip

    boost库,chm版,中文,有示例,有...含智能指针、函数对象、事件处理、字符串处理、多线程、异步输入输出、进程间通讯、文件系统、日期与时间、序列化、词法分析器、容器、数据结构、错误处理、类型转换操作符; 解压

    Effective C++(第三版)

    条款17:以独立语句将newed对象置入智能指针 store newed objects in smart pointers in standalone statements. 4. 设计与声明 designs and declarations 条款18:让接口容易被正确使用,不易被误用 make ...

    C++标准库介绍.pdf

    5个智能指针学习智能指针必读份不错参考是来自CUJ文章: Smart Poers in Boost,哦这篇文章可以查到CUJ是提供在线浏览中文版见笔者在Dr.Dobb\'s Journal软件 Software研发杂志第7辑上译文  Boost总体来说是实用价值很...

Global site tag (gtag.js) - Google Analytics