• c++101rule


    组织策略
    0,不拘于小结
    缩进, 行的长度,命名,注释,空格,制表,
    1-4,高警告级别干净利落地进行编译,使用构建系统,使用版本控制,代码审查
    风格
    5,一个实体应该只有一个紧凑的职责。 (依赖性管理,继承,抽象,隐藏)
    6,正确简单清晰
    7,




    ===================
    01, 视c++为一个语言联邦
    multiparadigm programming langauge, 支持过程(procedrual),面向对象object oriented, 函数形式functional
    ,泛型形式generic, 元编程metaprogramming
    02, 尽量用const 取代enumu,inline替换#define
    03, 尽量用const
    const成员函数目的,为了该成员函数作用于const对象身上
    两个函数如果常量性不同,可以被重载
    const对象大多数用于passed by poiner-to-const, passed by reference-to-const
    bit constness,成员函数只有在不更改任何non-static成员对象才可以说是const,也就是说不更改对象内任何一个bit.
    logical constness,一个const成员函数可以修改它所处理的对象内的某些bits,但只有客户端侦测不出的情况下才得如此。
    mutable 能够释放掉non-static 成员变量的bitwise constness约束。
    const char & operator[](std::size_t position) const
    {
        return text[position];
    }
    char & operator[](std::size_t position)
    {
        return const_cast<char&>(static_cast<const TextBlock&>)(this)[position]);
    }
    第一次转型static_cast<const TextBlock&>)(this)
    第二次转换const_cast<char&>
    利用const实现non const版本
    反向做法不可以。const成员函数承诺不改变其对象的逻辑状态(logical state),non-const成员函数没有这样的承诺。
    如果const调用non-const,就冒这样的风险:你曾经承诺不改动的那个对象被改动了。
    编译器强制实施bitwise constness, 编程应该使用概念上的常量性(conceptual constness)
    04, 确定对象使用前没初始化
    变量初始化规则,取决于变量类型和位置
    1)内置类型变量初始化取决于变量定义的位置,函数体外定义的变量都初始化成0,函数体里定义的内置类型不进行自动
    初始化。
    2)类类型变量的初始化,通过构造函数初始化(有默认/无默认需要显示调用)
    non-local-static 对象初始化顺序无法确定
    对应内置对象手工初始化
    使用成员初始值列表,不要在构造函数里面赋值,免除“跨编译单元之初始化次序”问题,用local static 对象替换
    non-local static对象
    05,了解c++默认编写哪些函数
    default构造函数,拷贝构造函数,拷贝赋值
    06,若不使用编译器自动生成的函数,就该明确拒绝。
    uncopable 将构造函数声明为private
    07,为多态声明virtual 析构函数
    08,别让异常逃离析构函数
    09, 绝不在构造函和析构过程中调用virtual函数
    可以用private static函数,作为辅助函数给base calss构造函数传值。
    10, 另operator= 返回一个reference to *this
    连锁赋值。这只是个协议,无强制性。内置标准类型和标准库都提供
    11,在Operator= 中处理自我赋值
    确定任何函数如果操作一个以上对象,其中多个对象是同一个对象时,执行仍然正确。
    12, 复制对象时勿忘其每一个成分
    1)复制local成员变量,2)base class内的coppying函数
    copy assignment调用copy构造函数是不合理的。因为这就像试图构造一个已经存在的对象。
    copy构造函数调用copy assignment操作同样无意义。 构造函数用来初始化新对象,而assginment
    操作只实施于已经初始化的对象上。对一个尚未构造好的对象赋值,就像在一个尚未初始化的对象上
    做“只对已经初始化对象才有意义”的事情一样。
    如果你发现copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,
    建立一个新的成员函数给两者调用。这样的函数往往是priviate,而且常命名init.
    1)copy函数应该确保复制对象内的所有成员变量及base成分
    2)不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放在第三个函数中,
    并由copying函数共同调用。

    资源管理
    文件描述符,互斥锁,图像界面字体笔刷,数据库,socket
    13, 以对象管理资源
    获得资源后立刻放进管理对象auto_ptr RAII resource acquisition is initialization
    管理对象运用析构函数确保资源释放
    RCSP reference-couting smart pointer RCSP无法打破环状引用。
    tr1::shared_ptr就是RCSP
    为了防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
    两个常被使用的RAII classes分别是tr1_shared_ptr和auto_ptr
    14, 在资源管理类中心小心copying行为
    15,在资源类中提供对资源的访问
    RAII class 应该提供取得其管理之资源的办法
    对原始资源的访问可能经由显示转换或隐士转换,一般而言显示转换比较安全,隐士转换对客户比较
    方便
    16,对使用new和delete要采用相同的形式
    delete pal; delete [] pal;
    17,以独立newed对象需要置入智能指针
    以独立语句将Newed对象置于智能指针内,如果不这样,一旦异常抛出,有可能导致难以觉察的资源泄漏
    设计与声明
    18,让接口容易被正确使用,不容易被误用
    理想上,如果客户企图使用某个接口却没有获得他所预期的行为,这个代码不应该通过编译,反之则是
    客户想要的
    接口一致性。尽量与内置types一致。
    限制类型内什么事可以做,什么不可以做,常用const限制。
    防止误用,包括建立新类型,限制类型上的操作,束缚对象值,消除客户端资源管理责任
    tr1::shared_ptr支持定制删除器,可以防范DLL问题,可被用来自动解除互斥锁。
    19 设计class犹如设计type
    重载函数,操作符,控制内存分配,定义对象初始化终结。
    新type的对象应该如何被创建销货
    对象的初始化和对象的赋值应该有什么样的差别。这个答案决定构造函数和赋值操作符的行为
    新type对象如果被passed by value,意味着什么? copy构造函数
    什么是typed的合法值。 class约束条件 invariants.
    你新type需要配合某个继续体系图么?
    你的type需要什么样的转换?
    什么样的函数对新type而言合理,memeber函数
    什么样的标准函数应该驳回, private函数
    谁该取用新type成员。public成员
    什么是新type的未声明接口
    你的新type有多么一般化 class template
    你需要一个新type么?
    20,宁以pass-by-reference-to-const 替换pass-by-value
    防止产生副本copy构造函数多次调用
    防止对象切割,子类被视为基类对象传递
    这个规则不适用于内置类型
    21, 必须返回对象时,别妄想返回其reference.
    绝不要返回Pointer或reference指向一个local stack对象,或返回reference指向
    一个heap-allocated对象,返回pointer或reference指向local static对象有可能
    同时需要多个这样的对象。
    22,将成员变量声明为private
    23,宁以non-member ,non-friend替换member函数
    数据以及操作数据的那些函数应该捆绑到一块。
    如果某些东西被封装,它就不再可见。愈多东西被封装,愈少人可以看到它。而遇少
    人看到它,我们就有愈大的弹性去变化它。因为我们改变仅仅直接影响看到改变的那些
    人和事物。因此,愈多东西被封装,我们改变那些东西的能力就愈大。封装使我们改变
    事物只影响有限客户。
    限制考虑对象数据,愈少代码可以看到数据(也就是访问它),愈多的数据可以被封装
    ,而我们也就遇能自由地改变对象数据,例如改变成员变量的数量,类型等等。如何测量
    “有多少代码可以看到一块数据”,我们计算能访问该数据的函数,作为一种粗糙的测量。
    愈多函数访问它,数据的封装性愈低。
    名字空间可以跨多个源文件,类不能,类是一个整体不能分割。
    prefer non-member non-friend to member,这样做增加封装性,包裹弹性,和机能扩充性。
    24,若所有参数皆需类型转换,请为此采用non-member函数
    只有参数被列入参数列,这个参数才是隐式类型转换的合格参与者。
    member的函数反面是non-member,而不是friend.
    不能够只因为不该成为member,就自动让它成为friend.朋友带来的麻烦往往过于其价值。
    25,考虑写出一个不抛出异常的swap函数。
    无法偏特化function template.只能对class template偏特化。
    可以重载function template

    std::swap 典型实现

    namespace std {

      template<typename T>

      void swap(T& a, T&b)

      {

        T temp(a);

        a = b;

        b = temp;

      }

    }

    如果不赋值,只想拷贝指针pimp.可以对std::swap特化,下面是基本构想,但目前无法通过编译

    namespace std{

      template<> void swap<Widget>(Widget &a, Widget& b)

      {

        swap(a.pmpl, b.pmpl);

      }

    }

    在Wiget类中加一个成员swap函数,这种做法同STL容器一致。

    class Widget {

      public:

        void swap(Widget & other)

        {

          using std::swap;

          swap(pImpl, other.pImpl);

        }

    };

    如果类Widget 和 WidgetImp是模板

    template<T>

    class WidgetImp {...};

    template<T>

    class Widget{...};无法在std内添加重载模板,违反标准。

    namespace WidgetStuf

    {

      ...

      template<typename T>

      class Widget {...};

      ...

      template<typename T>

      void swap(widget<T> a, widget<T>b)

      {

        a.swap(b);

      }

    }

    如果打算置换两个widget对象,根据c++名字查找法则 name lookups rules. argument-dependent lookup或koening lookup法则

    pimp pointer to implementation.

  • 相关阅读:
    mysql索引批量在postgres里面重建
    获取metabase用户信息
    metabase一个sql统计
    C笔记-左值与右值
    前端散记(不定时补充)
    推荐一本书 保险进行时
    怎么增加照片的KB大小
    Java 流(Stream)、文件(File)和IO
    Java HashMap 和 ConcurrentHashMap 以及JDK 1.7 和 1.8 的区别
    【一文整理:Google Big table 序列化组件 Protocol Buffers 的使用 】
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/6055074.html
Copyright © 2020-2023  润新知