条款26:尽可能延后变量定义式的出现时间


为何要尽量延后?

当程序中途跳出而导致变量未被使用,但是必须进行构造和析构。


最佳初始化变量

直接在构造时指定初值比构造之后再赋值效率高(条款4)

   ...
std::string encrypted(password);
...

循环内变量定义在循环内还是循环外?

程序A:定义于循环外

   //方法A:循环外定义
POINT point;
for (int i = 0; i < 1000000000; i++)
{
point = tmp;
//tmp = point;
}

程序B:定义于循环内

   //方法B:循环内定义
for (int i = 0; i < 1000000000; i++)
{
POINT point(tmp);
//tmp = point;
}

测试程序

   int PostponeVariable()
{
POINT tmp;
tmp.x = 12;
tmp.y = 13; clock_t start = clock();
//方法A:循环外定义
POINT point;
for (int i = 0; i < 1000000000; i++)
{
point = tmp;
//tmp = point;
}
clock_t end = clock();
printf("A:%ld\n", (end - start)); start = clock();
//方法B:循环内定义
for (int i = 0; i < 1000000000; i++)
{
POINT point(tmp);
//tmp = point;
}
end = clock();
printf("B:%ld\n", (end - start)); return 0;
}

结果

A:2953

B:2774

请按任意键继续. . .

全部都是A比B执行的快,之前一直自以为是的觉得放在循环外效率比较高!


条款27:尽量少做转型动作

  1. 尽量避免转型,特别是dynamic_casts,使用无转型设计代替有转型设计
  2. 一定要转型时,试着将其影藏于函数背后
  3. 尽可能使用C++新式转型

条款28:避免返回handles指向对象的内部

class Point{
public:
Point(int x, int y);
...
void setX(int newVal);
void setY(int newVal);
...
};
struct RectData{
Point ulhc;
Point lrhc;
};
class Rectangle{
...
Point& upperLeft()const {return pData->ulhc;}
Point& lowerRight()const {return pData->lrhc;}
private:
std::tr1::shared_ptr<RectData> pData;
};

const对象被修改:

Point coord1(0,0);
Point coord2(100,100);
const Rectangle rec(coord1, coord2);
rec.upperLeft().setX(50);//现在rec变成从(50,0)到(100,100)

修正:

class Rectangle{
...
const Point& upperLeft()const {return pData->ulhc;}
const Point& lowerRight()const {return pData->lrhc;}
private:
std::tr1::shared_ptr<RectData> pData;
};

避免返回指向对象内部部件的句柄(引用、指针或迭代器)。这样做可以增强封装性,帮助 const 成员函数拥有更加“ const ”的行为,并且使“野句柄”出现的几率降至最低。


条款29:为“异常安全”而努力

1. 修改菜单背景

class PrettyMenu{
public:
...
void changeBackground(std::istream& imgSrc);
...
private:
Mutex mutex;
Image* bgImage;
int imageChanges;
};
void PrettyMenu::changeBackground(std::istream& imgSrc)
{
lock(&mutex);
delete bgImage;
++imageChanges;
bgImage = new Image(imgSrc);
unlock(&mutex);
}

2. 异常安全条件

  • 不泄漏任何资源:若new Image(imgSrc)异常,则unlock永不解锁
  • 不允许数据破坏:若new Image(imgSrc)异常,则bgImage指向被删除的指针,且imageChanges已被修改,导致未成功执行却修改了数据。

3. 对象管理资源:解决资源泄漏

void PrettyMenu::changeBackground(std::istream& imgSrc)
{
Lock ml(&mutex);//来自条款14;
delete bgImage;
++imageChanges;
bgImage = new Image(imgSrc);
}

4. 异常安全函数保证

  • 基本承诺:异常抛出时,保持有效状态,没有对象或数据结构被破坏
  • 强烈保证:异常出现时,程序状态不改变,成功则完全成功,失败则会到之前状态
  • 不抛掷(nothrow)保证:承诺不抛出异常

5. 基本承诺

class PrettyMenu{
...
std::tr1::shared_ptr<Image> bgImage;
...
}; void PrettyMenu::changeBackground(std::istream& imgSrc)
{
Lock ml(&mutex);
bgImage.reset(new Image(imgSrc));
++imageChanges;
}

6. 强烈保证:copy and swap

struct PMImpl{
std::tr1::shared_ptr<Image> bgImage;
int imageChanges;
};
class PrettyMenu{
...
private:
Mutex mutex;
std::tr1::shared_ptr<PMImpl> pImpl;
};
void PrettyMenu::changeBackground(std::istream& imgSrc)
{
using std::swap;
Lock ml(&mutex);
std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl));
pNew->bgImage.reset(new Image(imgSrc)); //修改副本
++pNew->imageChanges;
swap(pImpl, pNew);//置换数据
}

Effective C++笔记(一)——条款26-29的更多相关文章

  1. Effective C++ 笔记:条款 32 确定你的public继承塑造出正确的is-a关系

    32 : Make sure public inheritance models "is-a." 0 引言 Inheritance and Object-Oriented Desi ...

  2. Effective C++ 笔记:条款 31 将编译关系降至最低

    31 : Minimize compilation dependencies between files 1 这关乎C++的类(或说都是类惹的祸) 1.1 C++类定义式的问题 C++类定义式不只叙述 ...

  3. Effective C++ 笔记:条款 30 inline

    30 : Understand the ins and outs of inlining 1 inline申请书 1.1 类内部实现函数包含隐藏的inline申请 class Human { publ ...

  4. Effective C++ 笔记:条款 34 实现继承和接口继承

    Differentiate between inheritance of interface and inheritance of implementation. 行为含义 声明一个pure virt ...

  5. Effective C++ 笔记:条款 33 避免继承导致的名称遮掩

    Avoid hiding inherited names 作用域(scopes)所带来的名称二义性,c++编译器会寻找指涉(refer to)的对象并实现名称遮掩规则(name-hiding rule ...

  6. EC读书笔记系列之14:条款26、27、28、29、30、31

    条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...

  7. [Effective JavaScript 笔记]第3章:使用函数--个人总结

    前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...

  8. Effective C++笔记:实现

    条款26:尽可能延后变量定义式的出现时间 博客地址:http://www.cnblogs.com/ronny/ 转载请注明出处! 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开 ...

  9. Effective C++笔记05:实现

    条款26:尽可能延后变量定义式的出现时间 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 有些对象,你可能过早的定义它,而在代码运行的过程中发生了导常,造成了開 ...

随机推荐

  1. [置顶] COcos2d-X 中文API

    本文来自http://blog.csdn.net/runaying ,引用必须注明出处! COcos2d-X 中文API 温馨提醒:使用二维码扫描软件,就可以在手机上访问我的博客啦!另外大家可以访问另 ...

  2. iOS开发常用国外网站清单

    工欲善其事必先利其器,最近发现临时查找一些东西容易浪费时间,花了点时间整理一下常用的网站,方便以后备用. 国内的code4app,ui4app,cocoachina,oschina,csdn就不说了, ...

  3. 斐波那契数列(fabnacci)java实现

    斐波那契数列定义:From Wikipedia, the free encyclopedia http://en.wikipedia.org/wiki/Fibonacci_number In math ...

  4. DecimalFormat用法

    DecimalFormat用法   DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字. DecimalFormat 包含一个模式 和一组符号 符号含义: ...

  5. systemd添加自定义系统服务设置自定义开机启动

    1.服务权限 systemd有系统和用户区分:系统(/user/lib/systemd/system/).用户(/etc/lib/systemd/user/).一般系统管理员手工创建的单元文件建议存放 ...

  6. mysql数据库安装方法

    前言 MySQL 有三种安装方式:RPM安装.二进制包安装.源码包安装.这3种种方式各有特色,主要特点参考下表.实际应用中,可以根据你所用的主机环境进行优化,选择 最佳的配置值,安装定制更灵活.访问M ...

  7. GSON 简介 示例

    Gson简介 目前解析json最常用的三种工具:org.json(Java常用的解析),fastjson(阿里巴巴出的),Gson(Google出的),解析速度最快的是Gson. Gson的全名为Go ...

  8. codevs 2241 排序二叉树

    /* WTF 写了好久了 开始的时候题目读错了 建图建错了 搜索写的也不好 感觉会T 总之 第一次写的很low 贴一下吧 */ #include<iostream> #include< ...

  9. IIS配置

    IIS配置文档: 1.安装IIS.控制面板→程序→打开关闭Windows功能,Web管理服务和万维网服务都勾上. 2.部署网站:ASP.Net项目的发布:项目中点右键“发布”,选择“文件系统”,发布到 ...

  10. python的数与字符串

    双引号 c1="sldkjf"print c1c2="It's a dog"print c2 单引号c1='sldkjf'print c1c2='It" ...