zoukankan      html  css  js  c++  java
  • Effective C++ 学习笔记

    基于此文档

    http://wenku.baidu.com/view/ef989106e87101f69e3195db.html

    条款13:以对象管理资源

    目标:为确保资源被释放

    1.获得资源后立即放进管理对象

    2.管理对象运用析构函数确保资源被释放

    做法:

    之前

    void f()
    {
        Investment *pInv = createInvestment();         // call factory function
        ...                                            // use pInv
        delete pInv;                                   // release object
    }
    

    之后

    void f()
    {
        std::auto_ptr<Investment> pInv(createInvestment());  
    }
    

    关于std::auto_ptr和std::tr1::shared_ptr用法不再叙述

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

    class Lock {
    public:
        explicit Lock(Mutex *pm)
            : mutexPtr(pm)
    
        { lock(mutexPtr); }                          // acquire resource
    
        ~Lock() { unlock(mutexPtr); }                // release resource
    
    private:
        Mutex *mutexPtr;
    
    };
    

    coping行为

    Lock ml1(&m);                      // lock m
    
    Lock ml2(ml1); 
    

    问题:“当一个RAII对象被复制,会发生什么事?”

    选择做法:

    1.禁止复制

    class Lock: private Uncopyable {            // prohibit copying — see
    public:                                     // Item 6
        ...                                        // as before
    
    };
    

    2.(最为普遍方法)利用std::tr1::shared_ptr的删除器做引用计数(当计数为0时调用的函数,但不删除指针)

    class Lock {
    public:
        explicit Lock(Mutex *pm)       // init shared_ptr with the Mutex
    
            : mutexPtr(pm, unlock)         // to point to and the unlock func
    
        {                              // as the deleter
            lock(mutexPtr.get());   // see Item 15 for info on "get"
    
        }
    private:
        std::tr1::shared_ptr<Mutex> mutexPtr;    // use shared_ptr
    };   
    

    3.深拷贝资源,但不用时要做删除动作

    4.利用auto_ptr做资源拥有权的转移

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

    如下代码

    std::tr1::shared_ptr<Investment> pInv(createInvestment());  // from Item 13
    
    int daysHeld(const Investment *pi);        // return number of days
    
    int days = daysHeld(pInv);                // error!
    
    int days = daysHeld(pInv.get());      
    

    两种方式:

    1.显示转换:get方法就是显示转换

    class Font {                           // RAII class
    public:
        ...                       // C API does
        FontHandle get() const { return f; }
    
    private:
        FontHandle f;                        // the raw font resource
        ...
    };
    changeFontSize(f.get(), newFontSize); // explicitly convert

    2.隐式转换

    class Font {
    
    public:
        ...
            operator FontHandle() const { return f; }        // implicit conversion function
        ...
    };
    
    changeFontSize(f, newFontSize);     // implicitly convert
    

    显然各有优缺点,但显示转换不易被误用,如std: string的显示转换方法

    条款17:以独立语句将newd对象置入智能指针

    int priority();
    
    void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);
    

    如何传参的问题:

    重点:保证传入的指针在异常的时候可以释放资源

    processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());
    
    

    以上做法可能有错误,如果执行顺序如下,而priority函数发生了错误,那么内存无法释放

    1. Execute "new Widget".

    2. Call priority.

    3. Call the tr1::shared_ptr constructor.

    保险的做法,在外部声明

    std::tr1::shared_ptr<Widget> pw(new Widget);  // store newed object
    
    processWidget(pw, priority());                // this call won't leak
    

    第四章:设计与声明

    这一章大多与设计有关

    条款18:让接口容易被正确使用,不易被误用

    让接口更易被理解和使用

    之前:

    class Date {
    public:
    
        Date(int month, int day, int year);
        ...
    };
    

    以类代替(请勿模仿,任何事物防不胜防,看需求而定)

    struct Day {            struct Month {                struct Year {
    
        explicit Day(int d)     explicit Month(int m)         explicit Year(int y)
    
            :val(d) {}              :val(m) {}                    :val(y){}
    
    
    
        int val;                int val;                      int val;
    
    };                      };                            };
    
    class Date {
    
    public:
    
        Date(const Month& m, const Day& d, const Year& y);
    
        ...
    
    };
    
    Date d(30, 3, 1995);                      // error! wrong types
    Date d(Day(30), Month(3), Year(1995));    // error! wrong types
    Date d(Month(3), Day(30), Year(1995));    // okay, types are correct
    

    条款 21:必须返回对象时,别妄想返回其reference

    拒绝一下两种写法,c#和java的开发者一定很不习惯

    const Rational& operator*(const Rational& lhs,   // warning! bad code!
    
        const Rational& rhs)
    
    {
        Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
        return result;
    }
    
    const Rational& operator*(const Rational& lhs,   // warning! more bad
    
        const Rational& rhs)   // code!
    
    {
        Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
        return *result;
    }
    

    必须要返回对象是,请返回一个新对象

    inline const Rational operator*(const Rational& lhs, const Rational& rhs)
    
    {
        return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
    }
    

    条款 22:将成员变量声明为private

    真的没什么好讲的,学过c#和java的人都知道

    class AccessLevels {
    
    public:
    
        ...
    
        int getReadOnly() const        { return readOnly; }
        void setReadWrite(int value)   { readWrite = value; }
        int getReadWrite() const       { return readWrite; }
        void setWriteOnly(int value)   { writeOnly = value; }
    
    private:
    
        int noAccess;                         // no access to this int
        int readOnly;                         // read-only access to this int
        int readWrite;                        // read-write access to this int
        int writeOnly;                        // write-only access to this int
    
    };
    

    条款 23:宁以non-member、non-friend替换member函数

    class WebBrowser {
    public:
        ...
    
        void clearCache();
        void clearHistory();
        void removeCookies();
    
        //void clearBrowser(WebBrowser& wb)
        //{
        //    wb.clearCache();
        //    wb.clearHistory();
        //    wb.removeCookies();
        //}
        ...
    
    };
    void clearBrowser(WebBrowser& wb)
    {
        wb.clearCache();
        wb.clearHistory();
        wb.removeCookies();
    }
    
    

    将便利函数放在外部,不要为类添加太多的类成员(意思就是只添加必要的),基本属于设计问题

    条款 24:若所有参数皆需类型转换,请为此采用non-member函数

    如下示例代码

    class Rational {
    public:
        Rational(int numerator = 0,        // ctor is deliberately not explicit;
            int denominator = 1);     // allows implicit int-to-Rational
    
        // conversions
    
        int numerator() const;             // accessors for numerator and
    
        int denominator() const;           // denominator — see Item 22
    
        const Rational operator*(const Rational& rhs) const;
    private:
        ...
    };
    

    其提供了隐式转换功能:

    Rational oneEighth(1, 8);
    Rational oneHalf(1, 2);
    
    Rational result = oneHalf * oneEighth;            // fine
    
    result = result * oneEighth;                      // fine
    

    更加贪婪的做法

    result = oneHalf * 2;                       // fine
    result = 2 * oneHalf;                       // error!
    

    为了支持2的隐式转换,做法是实现一个non-member的操作符重载

    const Rational operator*(const Rational& lhs,     // now a non-member
    
        const Rational& rhs)     // function
    
    {
        return Rational(lhs.numerator() * rhs.numerator(),
            lhs.denominator() * rhs.denominator());
    
    }
    Rational oneFourth(1, 4);
    
    Rational result;
    
    result = oneFourth * 2;                           // fine
    
    result = 2 * oneFourth;                           // hooray, it works!
    

    记得是所有参数

  • 相关阅读:
    [SQLSERVER2005 ERROR]"附加数据库 对于 服务器“GNPC”失败"
    家用视频监控设备
    Layer Two Tunneling Protocol "L2TP"
    [转]char类型和string类型(C++,C#)
    Layer 2 Tunneling Protocol
    坚持坚持。。。
    转载几篇有用的文章
    常用的SQL语句(转载)
    python判断一个字符是否是xml合法字符
    搜索引擎推荐
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2118806.html
Copyright © 2011-2022 走看看