条款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. Android---优化下载让网络访问更高效(三)

    批处理传输和连接 每次启动一个连接---跟传输的数据大小无关---在使用典型的3G无线信号时,就会潜在的导致无线信号消耗近20秒的电量. 如果一个应用程序每隔20秒ping一次服务器,只是告知该应用程 ...

  2. 一分钟明确 VS manifest 原理

    什么是vs 程序的manifest文件 manifest 是VS程序用来标明所依赖的side-by-side组建,如ATL, CRT等的清单. 为什么要有manifest文件 一台pc上,用一组建往往 ...

  3. 关于“无法解析的外部符号”和“该符号在函数_wmain 中被引用”的问题

    在VS2008和opendv的环境下: error LNK2019: 无法解析的外部符号_cvDestroyWindow,该符号在函数_wmain 中被引用 error LNK2019: 无法解析的外 ...

  4. 【解决】hive动态添加partitions不能超过100的问题

    Author: kwu [解决]hive动态添加partitions不能超过100的问题,全量动态生成partitions超过100会出现例如以下异常: The maximum number of d ...

  5. Meth | apt-get update ,upgarde 和dist-upgrade 的区别

    #sudo apt-get update 获得最近的软件包的列表:列表中包含一些包的信息,比如这个包是否更新过#sudo apt-get dist-upgrade 如果这个包没有发布更新,就不管它:如 ...

  6. 《UNIX网络编程》之多客户连接服务端,可重用套接字对

    该网络编程之客户端与服务端程序模板支持: 1. 多客户端同时连接服务端,即服务程序可以同时为多个客户端服务: 2. 服务端支持套接字对重用,即即使处于TIME_WAIT状态,仍可支持服务端重启: 3. ...

  7. 第四章:使用Proxy代理让客户端服务端分工合作。

    <基于1.8 Forge的Minecraft mod制作经验分享> 别被那个Proxy代理吓到,很简单的. 我们先讨论为什么要用Proxy代理: 像打开新的UI这种操作,比如打开一个背包, ...

  8. 第三章:真正弄清楚一个Mod的组织结构

    <基于1.8 Forge的Minecraft mod制作经验分享> 首先看看一个mod的文件结构,懂Java的应该都看得懂: src/main/ --java/com.xxxxxxxx.x ...

  9. 关于apache下同IP多域名支持HTTPS和80跳转HTTPS的配置

    httpd-ssl的配置: Listen 443 NameVirtualHost *:443 AddType application/x-x509-ca-cert .crt AddType appli ...

  10. MM32Flash读写操作(兼容STM32)

    MM32Flash读写操作(兼容STM32) Flash基础描述 思维导图 编程实现读写操作 主函数结构 #include "delay.h" #include "sys ...