body, table{font-family: 微软雅黑; font-size: 10pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

资源管理--RAII:
1、RAII(Resource Acquisition Is Initialization)是一种由 C++创造者 Bjarne Stroustrup 提出的, 利用对象生命周期管理程序资源(包括内存、文件句柄、锁等)的技术。
2、使用 RAII 时,一般在资源获得的同时构造对象, 在对象生存期间,资源一直保持有效;对象析构时,资源被释放。
关键:要保证资源的释放顺序与获取顺序严格相反
3、RAII类的常见特征
1、在构造时初始化资源, 或托管已构造的资源
2、析构时释放资源
3、一般不允许复制或赋值(对象语义)
4、提供若干访问资源的方法
4、RAII的本质是用栈对象来管理资源,因为栈对象在离开作用域时,会自动调用析构函数
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
class SafeFile
{
        public:
                SafeFile(const string & filename)
                :_fp(fopen(filename.c_str(),"w+"))
                {
                        cout<<"fopen(_fp)"<<endl;
                        if(NULL == _fp)
                        {
                                cout<< "FILE open error"<<endl;
                        }
                }
                ~SafeFile()
                {
                        if(_fp != NULL)
                        {
                                fclose(_fp);
                                cout<< "fclose(_fp) "<<endl;
                        }
                }

                void write(const char * str)
                {
                        cout<<"write(const char *)"<<endl;
                        if(fputs(str,_fp)==EOF)
                        {
                                cout<< "write error!" <<endl;
                        }
                }
        private:
                FILE * _fp;
                SafeFile(const SafeFile & rhs);
                SafeFile & operator = (const SafeFile & rhs);
};

int main()
{
        SafeFile sf("test.txt");
        sf.write("hello,world!\n");
        return 0;
}

/**
**利用一个对象在离开个域中会调用析构函数的特性,
**在构造函数中完成初始化,在析构函数中完成清理工作,将需要
**操作和保护的指针作为成员变量放入RAII中。
*/

#include<iostream>
using namespace std;
template<typename T>
class RALL
{
        public:
                RALL(T* p):_p(p)  { cout<<"托管资源"<<endl; }
                ~RALL()  // 托管资源,可能多个指针指向同一块内存区域,if判断不能发挥作用
                {
                        if(NULL!=_p)
                        {
                                delete _p;
                                _p=NULL;
                        } cout<<"释放资源"<<endl;
                }
                // 资源指针,被托管的都是资源的地址,
                // 所以要重载这些运算符,能够获取
                // 资源的地址
                T* get()const;
            T& operator*()const;  //目的就是返回托管的指针指向的值
            T* operator->()const;  // 似乎没怎么用到这个
                void reset(T* new_p);  // 更改托管资源地址
                void swap(RALL<T> &rhs);  // 交换地址
        private:
                RALL(const RALL<T>&);  //禁止调用拷贝构造函数
                RALL<T>& operator=(const RALL<T>&);  // 禁止调用赋值构造函数
        private:
                T* _p;  // _p指向被托管的资源
};
template<typename T>
T* RALL<T>::get()const
{
        return _p;
}
template<typename T>
T& RALL<T>::operator*()const
{
        return *_p;
}
template<typename T>
T* RALL<T>::operator->()const
{
        return _p;
}
        template<typename T>
void RALL<T>::reset(T* new_p)
{
        delete _p;
        _p = new_p;
}
        template<typename T>
void RALL<T>::swap(RALL<T> &rhs)
{
        std::swap(_p,rhs._p);
}

#include<iostream>
#include"RALL.h"
using namespace std;
class resource
{
        public:
                resource(){cout<<"resource::resouce()"<<endl;}
                ~resource(){cout<<"resource::~resource()"<<endl;}
        private:
};
class test
{
        public:
                test():_p(new resource){ cout<<"test::test()"<<endl; }
             ~test(){ cout<<"test::~test()"<<endl; }
                //拷贝构造函数
                //RALL类重载了*运算符,这里new的同时
                //直接用rhs的值来初始化新开辟的空间
                test(const test& rhs):_p(new resource(*rhs._p))
                { cout<<"test::test(const test&)"<<endl; }
//                test& operator=(const test& rhs)
//                {
//                        cout<<"test::operator=(const test&)"<<endl;
//                        if(this==&rhs){return *this;}
//                        //delete this->_p.get();
//                        //*_p = *(rhs._p);
//                        _p.reset((rhs._p).get());  // 函数里面已经写了释放
//                        return *this;
//                }
        private:
                test& operator=(const test& rhs);  // 赋值构造函数造成多个指针指向一块区域
                // dubble free
        private:
                RALL<resource> _p;
};
int main()
{
        test em;
        cout<<"--------------------------"<<endl;
        test em2;
        cout<<"**************************"<<endl;
        //em2 = em;  // 这里赋值了会导致em2和em释放,段错误
        //后面我在RALL类里面的析构函数做了特殊处理,指针为NULL才delete
//结果没考虑多个指针指向一块区域
        cout<<"准备开始释放资源:"<<endl;
        return 0;
}


资源管理--智能指针:
      ——是存储指向动态分配(堆)对象指针的类
      ——在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象
      ——RAII类模拟智能指针
C++11提供了以下几种智能指针,位于头文件  #include<memory> ,它们都是类模板
std::auto_ptr(复制/赋值)   现在已淘汰
std::unique_ptr  c++11
std::shared_ptr  c++11
std::weak_ptr    c++11
g++ -std=c++11 xx.cc
1、std::auto_ptr在构造时获取对某个对象的所有权(ownership),在析构时释放该对象
2、std::auto_ptr要求其对“裸”指针的完全占有性---->
      ——在拷贝构造或赋值操作时,会发生所有权的转移      //两次使用auto_ptr,第一次的会转移,转移了之后就失效了,其后不能使用,只能最终获得转移权的智能指针使用
3、本身存在缺陷
#include <iostream>
#include <memory>
using namespace std;
int main()
{
        double * pd = new double(88.99);
        auto_ptr<double> app(pd);
        cout<<"*app = "<<*app<<endl;
        cout<<"app.get()= "<<app.get()<<endl;
        cout<<"pd       = "<<pd<<endl;
        int * pi = new int(5);
        auto_ptr<int> api(pi);
        auto_ptr<int> api2(api);   //这里实际上是拷贝
        //表达的是值语义,但是实现有缺陷,在底层已经发生了所有权的转移
        cout<<"*api2 = "<<*api2<<endl;
        cout<<"*api = "<<*api<<endl;  //段错误,api已经不能在使用了
        return 0;
}


4、std::unique_ptr是一个独享所有权的智能指针,它提供了一种严格语义上的所有权,包括:
     ——拥有它所指向的对象
     ——无法进行复制、赋值操作
     ——保存指向某个对象的指针,当它本身被删除释放的时候,会使用给定的删除器释放它指向的对象
     ——具有移动(std::move)语义(和前面的把左值改右值一样),可做为容器元素
1.无法进行复制、赋值操作
  std::unique_ptr<int> ap(new int(88 );
  std::unique_ptr<int> one (ap) ; // 会出错
  std::unique_ptr<int> two = one; //会出错

3.可做为容器元素
  unique_ptr<int> sp(new int(88));
  vector<unique_ptr<int> > vec;
  vec.push_back(std::move(sp));
  //vec.push_back( sp ); 这样不行,会报错的.
  //cout<<*sp<<endl;但这个也同样出错,说明sp添加到容器中之后,它自身报废了.

2.可以进行移动构造和移动赋值操作
 unique_ptr<int> GetVal( ){
    unique_ptr<int> up(new int(88 );
    return up;
 }
 unique_ptr<int> uPtr = GetVal();   //ok
 实际上上面的的操作有点类似于如下操作
 unique_ptr<int> up(new int(88 );
 unique_ptr<int> uPtr2 = std::move(up) ; //这里是显式的所有权转移. 把up所指的内存转给uPtr2了,而up不再拥有该内存.
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
unique_ptr<int> getValue()
{
        unique_ptr<int> upi(new int (88));
        return upi;  //最后获得的是一个右值
}
int main()
{
//unique_ptr无法进行复制或赋值,表达的是对象语义
        unique_ptr<int> one(new int(1));
        //无法进行复制、赋值操作
//        unique_ptr<int> two(one);   //错
//        unique_ptr<int> three=one; //错
 
//可以进行移动构造和移动赋值操作
// 调用的是移动构造函数
        unique_ptr<int> tmp = getValue();
        unique_ptr<int> up(new int(88));
        unique_ptr<int> up2 = move(up); 
//这里把显示的左值所有权转移,把up所指的内存转移给up2,而up不再拥有该内存
//    cout<<" *up = "<<*up<<endl;  //段错误,move之后不能再使用
        //可做为容器元素
       unique_ptr<int> sp(new int(33));
       vector<unique_ptr<int> > vec;
        vec.push_back(move(sp));     //必须转换成右值
//     cout<<*sp<<endl;      //段错误,在添加到容器的过程中转换成右值,自身不再拥有内存
        return 0;
}


5、std::shared_ptr是一个引用计数智能指针,用于共享对象的所有权
     ——引进了一个计数器shared_count,用来表示当前有多少个智能指针对象共享指针指向的内存块
     ——析构函数中不是直接释放指针对应的内存块,如果shared_count大于0则不释放内存只是将引用计数减1,只有计数等于0时释放内存
     ——复制构造与赋值操作符只是提供一般意义上的复制功能,并且将引用计数加1.
     ——问题:循环引用(最终导致内存泄露)
#include<iostream>
#include<memory>
using namespace std;
int main()
{
        shared_ptr<int> sp(new int(1));
        cout<<"*sp="<<*sp<<"  sp.use_count="<<sp.use_count()<<endl;
        shared_ptr<int> sp2 = sp;  // 赋值,只是引用计数增加1
        cout<<"*sp="<<*sp<<"  sp.use_count="<<sp.use_count()<<endl;
        cout<<"*sp2="<<*sp2<<"  sp2.use_count="<<sp2.use_count()<<endl;
}

6、std::shared_ptr是强引用智能指针
强引用,只要有一个引用存在,对象就不能被释放

#include <iostream>
#include <memory>
using namespace std;
class Parent;    //前向声明
class Child
{
        public:
                Child()   {  cout<< "Child()" <<endl;  }
                ~Child()  {  cout<< "~Child()" <<endl; }
                shared_ptr<Parent> _parentPtr;
};
class Parent
{
        public:
                Parent()  {  cout<< "Parent()" <<endl;  }
                ~Parent() {  cout<< "~Parent()" <<endl; }
                shared_ptr<Child> _childPtr;
};
int main()
{//问题是:循环引用,发生内存泄露
        shared_ptr<Parent> parentPtr(new Parent);
        shared_ptr<Child> childPtr(new Child);
        cout<< "parent' use_count()= "<<parentPtr.use_count()<<endl;
        cout<< "child' use_count()= "<<childPtr.use_count()<<endl;
        parentPtr->_childPtr = childPtr;
        childPtr->_parentPtr = parentPtr;
        cout<< "parent' use_count()= "<<parentPtr.use_count()<<endl;
        cout<< "child' use_count()= "<<childPtr.use_count()<<endl;
        return 0;
}


7、std::weak_ptr 是弱引用智能指针
     ——强引用,只要有一个引用存在,对象就不能被释放
     ——弱引用,并不增加对象的引用计数,但它知道对象是否存在。如果存在,提升为shared_ptr成功;否则,提升失败
     ——通过weak_ptr访问对象的成员的时候,要提升为shared_ptr
shared_ptr的误用
class std::enable_shared_from_this
方法shared_from_this()
删除器
#include <iostream>
#include <memory>
using namespace std;
class Parent;    //前向声明
class Child
{
        public:
                Child()   {  cout<< "Child()" <<endl;  }
                ~Child()  {  cout<< "~Child()" <<endl; }
                weak_ptr<Parent> _parentPtr;    //弱引用  
};
class Parent
{
        public:
                Parent()  {  cout<< "Parent()" <<endl;  }
                ~Parent() {  cout<< "~Parent()" <<endl; }
                shared_ptr<Child> _childPtr;
                //weak_ptr<Child> _parentPtr;  
};
int main()
{//问题是:循环引用,发生内存泄露;使用weak_ptr能够打破循环引用
        shared_ptr<Parent> parentPtr(new Parent);
        shared_ptr<Child> childPtr(new Child);
        cout<< "parent' use_count()= "<<parentPtr.use_count()<<endl;
        cout<< "child' use_count()= "<<childPtr.use_count()<<endl;
        parentPtr->_childPtr = childPtr;
        childPtr->_parentPtr = parentPtr;
        cout<< "parent' use_count()= "<<parentPtr.use_count()<<endl;
        cout<< "child' use_count()= "<<childPtr.use_count()<<endl;
        return 0;
}

#include<iostream>
#include<memory>
using namespace std;
class X
{
        public:
                X(){ cout<<"X()"<<endl; }
                ~X(){ cout<<"~X()"<<endl; }
                void fun(){ cout<<"X::fun()"<<endl; }
};

int main()
{
        weak_ptr<X> wp;
        {
                cout<<"wp use count="<<wp.use_count()<<endl;  // weak_ptr没有get成员
                cout<<endl;
                shared_ptr<X> sp(new X);
                cout<<"addr ap="<<sp.get()<<"  sp use count="<<sp.use_count()<<endl;
                cout<<endl;
                wp = sp;  // 并没有增加引用计数
                cout<<"addr ap="<<sp.get()<<"  sp use count="<<sp.use_count()<<endl;
                cout<<"wp use count="<<wp.use_count()<<endl;
                cout<<endl;
                shared_ptr<X> sp2 = wp.lock();  // 弱引用要提升为强引用才能访问托管对象
                cout<<"addr ap="<<sp.get()<<"  sp use count="<<sp.use_count()<<endl;
                cout<<"wp use count="<<wp.use_count()<<endl;
                cout<<"addr sp2="<<sp2.get()<<"  sp2 use count="<<sp2.use_count()<<endl;
                if(!sp2){  cout<<"object is destroyed!"<<endl;  }
                else
                { // 引用计数+1
                        sp2->fun();
                        cout<<"weak_ptr lock 成功"<<endl;
                }
        }  // 离开作用域,sp、sp2被释放  weak_ptr知道自己托管的对象是否释放了

        cout<<endl;
        shared_ptr<X> sp3 = wp.lock();  // new X的对象已经释放了,提升失败
        if(!sp3){  cout<<"object is destroyed!"<<endl;  }
        else
        { 
                sp3->fun();
                cout<<"weak_ptr lock 成功"<<endl;
        }
        cout<<"wp use count="<<wp.use_count()<<endl;
        cout<<"addr sp3="<<sp3.get()<<"  sp3 use count="<<sp3.use_count()<<endl;
        return 0;
}

8、shared_ptr的误用
     ——class std::enable_shared_from_this
     ——方法  shared_from_this()
     ——删除器
class A:public enable_share_from_this<A>

使用场合:当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。
我们就使类A继承enable_share_from_this,然后通过其成员函数share_from_this()返回当指向自身的share_ptr。
以上有2个疑惑:
1.把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?
    一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_ptr此时还指向该对象。
2.这样传递share_ptr可以吗?share_ptr<this>
    这样会造成2个非共享的share_ptr指向一个对象(拷贝)(一个指针被两个对象托管),最后造成2次析构该对象。
#include<iostream>
#include<memory>
using namespace std;
class point:public enable_shared_from_this<point>
{
        public:
                point(int x=0,int y=0):_x(x),_y(y)
                { cout<<"point(int,int)"<<endl; }
                ~point()  { cout<<"~point()"<<endl; }
#if 0
                point* add(const point* rhs)
                {
                        _x += rhs->_x;
                        _y += rhs->_y;
                        return this;
                }
#endif
                shared_ptr<point> add(const point* rhs)
                {
                        //在类内部进行托管
                        _x += rhs->_x;
                        _y += rhs->_y;
                        //return shared_ptr<point>(this); 
// 和point* add(cosnt point*)一个效果。
                        return shared_from_this();
                        //这个方法在enable_shared_from_this<class T>中
                }
                friend ostream& operator<<(ostream& ,const point&);
        private:
                int _x;
                int _y;
};
ostream& operator<<(ostream& os,const point& rhs)
{
        os<<"("<<rhs._x<<","<<rhs._y<<")";
}

void test1()//对shared_ptr误用
{ //1、对shared_ptr的误用
        point* p1 = new point(1,2);
        shared_ptr<point> sp1(p1);
        cout<<"sp1 use count="<<sp1.use_count()<<endl;
        shared_ptr<point> sp2(p1);  //只有sp2 = sp1才会提升引用计数
//      shared_ptr<point> sp2(sp1);  //这样也会提升引用计数
        //重复对一个对象托管,会导致多次调用析构函数
        cout<<"sp1 use count="<<sp1.use_count()<<endl;
        cout<<"sp2 use count="<<sp2.use_count()<<endl;
}
void test2()
{
        shared_ptr<point> p1(new point(1,2));
        shared_ptr<point> p2(new point(3,4));
        cout<<"p1 use count="<<p1.use_count()<<"  p2 use count="<<p2.use_count()<<endl;
        p2.reset(p1.get());  // reset先释放p2,在把p1的值赋给p2
        cout<<"addr p1="<<p1<<endl;
        cout<<"addr p2="<<p2<<endl;
        cout<<"p1 use count="<<p1.use_count()<<"  p2 use count="<<p2.use_count()<<endl;
}
void test3()
{   
        shared_ptr<point> p1(new point(1,2));     
        shared_ptr<point> p2(new point(3,4));    
        //误用, p1和p3同时托管一个对象   
        shared_ptr<point> p3(p1->add(p2.get()));   
        cout<<"p1 use count="<<p1.use_count()<<endl;   
        cout<<"p2 use count="<<p2.use_count()<<endl;   
        cout<<"p3 use count="<<p3.use_count()<<endl;         
        cout<<"p1="<<p1<<"  p2="<<p2<<"  p3="<<p3<<endl;   
}
int main()
{
        //test1();  // 这里test1()和test2()同时打开段错误,不知道为啥
        cout<<"---------------"<<endl;
        //test2();  // 和上面同样的原因,我猜测是前面开辟的堆内存没有释放,后面又要来delete,所以出现错误。
        cout<<"---------------"<<endl;
        test3();
        return 0;
}

//point(int,int)
//sp1 use count=1
//sp1 use count=1
//sp2 use count=1
//~point()
//~point()
//---------------
//point(int,int)
//point(int,int)
//p1 use count=1  p2 use count=1
//~point()
//addr p1=0x244e030
//addr p2=0x244e030
//p1 use count=1  p2 use count=1
//~point()
//~point()
//---------------
//point(int,int)
//point(int,int)
//p1 use count=1
//p2 use count=1
//p3 use count=1
//p1=0xbd5030  p2=0xbd5070  p3=0xbd5030
//~point()
//~point()
//~point()
//采用返回shared_from_this()
//---------------
//point(int,int)
//point(int,int)
//p1 use count=2
//p2 use count=1
//p3 use count=2
//p1=0xc2f030  p2=0xc2f070  p3=0xc2f030
//~point()
//~point()

#include <iostream>
#include <stdio.h>
#include <memory>
using namespace std;
struct Fpcloser
{
        void operator()(FILE * fp)
        {
                if(fp)
                {
                        cout<<"release file pointer!"<<endl;
                        fclose(fp);
                }
        }
};
void test0()
{//自己指定删除器
        unique_ptr<FILE,Fpcloser> up( fopen("test.txt","w+"),Fpcloser() );
        fputs("hello,world\n",up.get());     //get()返回托管对象的指针
}
void test1()
{//指定删除器的方式
        shared_ptr<FILE> sp(fopen("test.txt","r+"),Fpcloser());
        char buff[1024];
        fgets(buff,sizeof(buff),sp.get());
        cout<<buff;
}
int main()
{
        //test0();
        test1();
        return 0;
}

资源管理
》原理:利用栈对象去管理资源;栈对象的特性是创建对象是自动调用构造函数,当其生命周期结束时,会自动调用析构函数
》RALL
》智能指针
   auto_ptr  (已被废弃)
   unique_ptr
   shared_ptr
   weak_ptr

最新文章

  1. Jquery操作select
  2. 有关DTCoreText无法加载网络图片及应用问题
  3. float包裹性与破坏性及清除浮动几种方法
  4. GCC 源码编译 mpc mprf gmp 不用make(否则会有lib/libgmp.so: could not read symbols: File in wrong format等错误)
  5. 操作系统开发系列—13.a.进程 ●
  6. BP(back propagation)反向传播
  7. 发布 PM2.5 数据的城市列表
  8. Device eth0 does not seem to be present,delaying initialization解决方法
  9. 创建和使用Windows静态链接库
  10. php中curl和fsockopen发送远程数据的应用
  11. CSS 加载新方式
  12. PaaS平台资源
  13. 用shell获取文件大小
  14. android 检测是否插入U盘方法之一
  15. 从Myeclipse到Intelj Idea
  16. 纯js无缝滚动
  17. react-native 插件汇总
  18. Java获取正在执行的函数名
  19. WebFlux Spring Security配置
  20. Network of Schools---poj1236(强连通分量)

热门文章

  1. JAVA优化技巧分享 让游戏更加的流畅
  2. (转)帮你深入理解OAuth2.0协议
  3. PAT 1046 Shortest Distance[环形][比较]
  4. jQuery实现节点克隆、替换和互换
  5. NPOI+反射+自定义特性实现上传excel转List及验证
  6. 32Sql数据库的插入
  7. 在Qt中如何编写插件,加载插件和卸载插件(转)
  8. HDU1087
  9. 20145105 《Java程序设计》第5周学习总结
  10. 2017-2018-1 Java小组-1623 第一周作业