effective c++读书笔记(四)

条款26

尽可能延后变量定义式的出现

//方法A:定义循环外
Widget w;
for (int i = 0; i < n; ++i) 


      w =
 some value dependent on i;
        ...

}     //1个构造函数+1个析构函数+n个赋值操作;
//方法B:定义循环外
for (int i = 0; i < n; ++i) 
{
     Widget w(some value dependent on i);  
        ...
}     //n个构造函数+n个析构函数

除非:1.你知道赋值成本比“构造+析构”成本低;2.你正在处理代码中效率高度敏感的部分,否则应该使用方法B。

条款27

尽量少做转型动作

static_cast:将非const对象转换为const

static_cast<Window>(*this).onSize();//调用的实际上是一个临时对象的方法,与本对象无关

class specialwindow:public window

{

public:

virtual void onResize()

{

window::onResize();//调用父类的方法

}

}

dyamic_cast会基于class名称字符串比较;


class window{...};

class specialwindow:public window

{

public blink();

};

typedef std::vector<std::r1::shared_ptr<window>> VPM;

VPM winPtrs;

...

for(VPM::iterator iter=winPtrs.begin();iter!=winPtrs.end();++iter)

{

if(specialwindow * psw = dynamic<specialwindow *>(iter->get()))

psw->blink();

}//此方法不推荐,因为用到了转型

推荐做法:

typedef std::vector<std::tr1::shared_ptr<specialwindow>> VPSW;

VPSW winptrs;

for(VPSW::iterator iter=winptrs.begin();iter!=winptrs.end();++iter)

(*iter)->blink();//此种做法要对所有派生类提供vector

推荐做法二:

利用虚函数,代码略

条款28//引用点击打开链接

避免返回handle指向对象内部成分

 struct RectData 

  { 
        Point ulhc; 
        Point lrhc; 
   }; 
  class Rectangle 
    {
        public: 
            ... 
            Point&
 upperLeft() const { return pData->ulhc; }1//const只对函数内进行保护,函数返回后呢??
            Point&
 lowerRight() const { return pData->lrhc; }2 //const只对函数内进行保护,函数返回后呢??
        private: 
            std::tr1::shared_ptr<RectData> pData; 
            ... 
    }; 
    1,2两函数都返回引用,指向private内部数据,调用者于是可通过这些引用更改内部数据!这严重破坏了数据的封装性,对私有成员进行直接操作?太不可思意了!
     const Point& upperLeft() const { return pData->ulhc; }3
       const Point& lowerRight() const { return pData->lrhc; }    
      或者将1,2改为3,4,这就限制了客户的“涂改权”,只有“读取权”。
    但终究“返回一个handle代表对象内部成分”总是危险的。特别是将返回的指针或引用赋值给其它指针或引用,那么久造成了“悬空”。

条款29

为“异常安全”而努力是值得的

在抛出异常时,带有异常安全性的函数会:

1.不泄露任何资源

2.不允许数据败坏

异常安全函数提供以下三个保证之一:

基本承诺

强烈承诺

不抛出保证,总是能完成原先承诺的功能

int dosomething() throw();不抛出异常

throws(...);抛出所有异常

实例代码:p130,p131

条款30//引用点击打开链接

透彻了解inlining的里里外外

     Inline函数,多棒的点子!它们看起来像函数,动作像函数,比宏好得多,可以调用它们又不需蒙受函数调用所招致的额外开销。你实际获得的比想象的还多,编译器有能力对执行语境相关最优化。然而编写程序就像现实生活一样,没有白吃的午餐。inline函数也不例外,这样做可能增加你的目标码。
     如果inline函数的本体很小,编译器针对“函数本体”所产生的码可能比针对“函数调用”所产出的码更小。果真如此,将函数inlining确实可能导致较小的目标码和较高的指令高速缓存装置击中率。
     记住,inline只是对编译器的一个申请,不是强制命令。这项申请可以隐喻提出,也可以明确提出。隐喻方式是将函数定义于class定义式内,这样的函数通常是成员函数,friend函数也可被定义于class内,如果真是那样,它们也是被隐喻声明为inline。明确声明inline函数的做法则是在其定义式钱加上关键字inline。
     Inline函数通常一定被置于头文件内,因为大多数建置环境在编译过程中进行inlining,而为了将一个“函数调用”替换为“被调用函数的本体”,编译器必须知道那个函数长什么样子。
     Template通常也被置于头文件内,因为它一旦被使用,编译器为了将它具现化,需要知道哦啊它长什么样子。
     Template的具现化与inlining无关。如果你正在写一个template而你认为所有根据此template具现出来的函数都应该inlined,请将此template声明为inline;但如果你写的template煤油理由要求它所具现的每一个函数都是inlined,就应该避免将这个template声明为inline。
     一个表面上看似inline的函数是否真实inline,取决于你的建置环境,主要取决于编译器。
     有的时候虽然编译器有意愿inlining某个函数,还是可能为该函数生成一个函数本体(函数指针,构造函数,析构函数)。
     对程序开发而言,将上述所有考虑牢记在新很是重要,但若从纯粹实用观点出发,有一个事实比其它因素更重要:大部分调试器面对inline函数都束手无策。
     这使我们在决定哪些函数该被声明为inline而哪些函数不该时,掌握一个合乎逻辑的策略。一开始先不要将任何函数声明为inline,或至少将inlining施行范围局限在那些“一定成为inline”或“十分平淡无奇”的函数身上。

条款31

将文件的编译依存关系降至最低

如果使用object reference或者object pointers可以完成任务,就不要使用objects

如果能够,尽量以class声明式替换class定义式

为声明式和定义式提供不同的头文件



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值