Effective C++学习第五天

条款14:在资源管理类中小心copy行为

          当我们深入理解“资源取得时机是初始化时机(RAII)”概念,并以此作为“资源管理类”的核心时,我们可能会遇到将RAII对象复制的情况,一般有两种情况处理这个现象:1)如果我们的RAII对象是唯一的,那么复制就不合理,因此我们应该禁止copy构造的行为,正确的处理方式:将copy函数定义为private(base class),并用derived class private继承这个函数来阻止copy行为;  2)使用引用计数法,即智能指针的形式来实现对所有拷贝资源的追踪,但是智能指针的缺省行为是当引用次数为0时删除其所指向的对象。如果我们要实现的功能不是释放资源,这时候就应该自定义智能指针的deleter(一个函数或者函数对象),当引用次数为0时调用这个函数实现相应功能,如:

class lock{

public:

         explicit lock(mutex *pm) : mutexptr(pm,unlock) { }  //用mutex初始化shared_ptr,并以unlock函数为删除器

private:

                 std::tr1::shared_ptr<mutex>mutexptr;

};

另外,上述例子中不需要声明析构函数,因为class 析构函数会自动调用其non-static成员变量的析构函数;3)复制底部资源,采用深度拷贝的方法;4)采用转移底部资源拥有权的方法,也就是所谓的auto_ptr指针;

条款15:在资源管理类中提供对原始资源的访问

          当你需要访问一个RAII class对象的内部原始资源时,有两种方法可以达成目标:1)在类的内部提供一个get成员函数,用来执行显示转换,也就是返回类内部指针的原始复件;2)允许隐式转换到底部原始指针;在智能指针中,重载了指针取值操作符(operator->和operator*)来实现隐式转换;对于一般的来说,可以在类中提供一个隐式转换函数;如:

class font{

public:                                                                        //显示转换函数:

            explicit font(fonthandle fh) : f(fh){ }                fonthandle get() const {   return f;  }

            ~font() { releasefont(f); }                            //隐式转换函数  

private:                                                           operator fonthandle() const {return f;}//没太明白怎么隐式转换的

          fonthandle f;                                                                                                      //operator起到什么作用?

}

//显示转换                                                                   //隐式转换

void changefontsize(fonthandle f,int newsize);          void changefontsize(fonthandle f,int newsize);

font f(getfont());                                                       font f(getfont());

changefontsize ( f.get(), newfontsize);                      changefontsize ( f, newfontsize);

//但隐式转换会出一个问题

font f1(getfont());    

fonthandle f2=f1;   //原意是拷贝,结果是f1先转化为底部的fonthandle,然后拷贝,一旦此时f1被销毁,f2就处于指向资源被释放的状态(dangle)

条款16:成对使用new和delete时采取相同的方式

               如果你在new的表达式中使用[ ],则必须在相应的delete表达式中也使用[ ],如果没有使用[ ],那么也一定不要在delete中使用[ ];

条款17:以单独语句将newed对象置入智能指针中

          对于以下代码分析;

            int priority( );

           void processwidget(std :: tr1 :: shared_ptr<wideget>pw,int priority);

            //调用时   processwidget(new widget, priority( ));//编译错误,shared_ptr构造函数是explicit类型,不允许隐式转换

           //processwidget(std :: tr1 :: shared_ptr<wideget>(new widget),priority( ) );

           这个函数在调用processwidget之前,编译器必须创建代码,完成以下三件事情:1)调用priority;2)执行new widget;3)调用 std::tr1::shared_ptr构造函数;但是1)和2)的执行顺序和编译器有关,如果先执行2)后执行1),且在执行1)的时候发生异常,那么new widget返回的指针就会失效,那么内存泄露就产生了;

          解决上述问题的方法:使用分离语句,把创建对象和给智能指针赋初值的语句分离出来,原因是:编译器对于“跨越语句的各项操作”没有重新排列的自由(只有在语句内才拥有那个自由度);代码如下:

         std::tr1::shared_ptr<widget>pw(new widget);

          processwidget(pw,priority( ));

猜你喜欢

转载自blog.csdn.net/xx18030637774/article/details/80786305