zoukankan      html  css  js  c++  java
  • Effective C++笔记(一)——条款26-29

    条款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
    ", (end - start));
    
    	start = clock();
    	//方法B:循环内定义
    	for (int i = 0; i < 1000000000; i++)
    	{
    		POINT point(tmp);
    		//tmp = point;
    	}
    	end = clock();
    	printf("B:%ld
    ", (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);//置换数据 
    }
    
  • 相关阅读:
    动态数组的实现案例
    随机验证码实现案例
    wince下的CPU和内存占用率计算
    RT-Thread--时间管理
    RT-Thread--线程管理
    RT-Thread--内核基础
    RT-Thread--简介
    Git基本操作
    STM32F103/429串口IAP+Ymodem升级
    KEIL_MDK生成Bin文件
  • 原文地址:https://www.cnblogs.com/skywatcher/p/4045419.html
Copyright © 2011-2022 走看看