• 读书笔记之:Exceptional C++ Style (2004) [++]


    1. vector中元素的访问:[]与at操作

    2. 调整vector的大小:reserve

    reserve是保证vector的容量至少为某个值,它不会减少vector的容量。

    resize是改变vector的大小,这个操作比较严格,给出多少,结果vector的容量就变为多少。

    3. sprint的替代方案

    4. 定位new表达式

    5. 模板特化与函数重载

    类模板可以被偏特化或者全特化,函数模板则只能够被全特化

    重载决议只决定选出主模板

    分析下面的代码:

    #include <iostream>
    using namespace std;
    template <class T>
    void f(T){
        cout<<"f(T)"<<endl;
    }
    template <class T>
    void f(T*){
        cout<<"f(T*)"<<endl;
    }
    template<>
    void f<int>(int*){
        cout<<"f<int>(int*)"<<endl;
    }
    template<>
    void f<int*>(int*){
        cout<<"f<int*>(int*)"<<endl;
    }                              
    int main(){
        int *p;
        f(p);
    }

    程序运行结果是:f<int>(int*)

    即调用的是第3个函数。

    这儿容易让人疑惑的是,为什么不是第4个函数:template<>void f<int*>(int*) 呢?这个是template <class T>void f(T)的模板特化啊。

    要理解这个就需要注意一点:带有函数模板的重载进行决议的时候,选择的规则是首先选择最优的普通函数,如果没有适合的普通函数那么就要从模板函数中选择。而进行选择的时候,是决定选择的哪个主模板函数,然后再看这个主模板函数是否存在对应的特化。所以,对于上面的选择,首先是在

    template <class T>

    void f(T)

    template <class T>

    void f(T*)

    之间进行选择,发现第2个更加合适,这样就确定了主模板函数,然后在查找该主模板函数是否有对应的特化函数,这样正好找到了

    template<>

    void f<int>(int*)

    它是对int的特化,所以最后选择了这个函数。

     

    分开看是如下:

     

    6. 异常使用的正确位置

    资源获取即初始化RAII

    尽量通过析构函数来进行异常环境下的自动清理工作,而不是通过try/catch块

    永远不要允许析构函数、释放操作(deallocation)以及swap()函数抛出任何异常,因为否则的话,就没法安全且可靠地进行资源的清理了。

     

    7. 违反异常规格

    C++中的一些比较不起眼的特性,逐渐被尘封在语言的角落,直到许多人甚至于忘记了它们的存在。这正是为什么你看到的关于它们的文章总是相对较少,譬如像valarray、bitset、locale以及实际上是合法的表达式"5[a]"这些冷僻的特性。而对于异常规格来说同样如此。

    如果函数违反了异常规格的话,该函数肯定不能够以通常的函数返回方式返回,而它做的事情有如下两件:

    8. 类继承中构造顺序

     

    验证程序如下:

    #include <iostream>
    using namespace std;
    class B1{
        public:
        B1(){ cout<<"Constructor:B1()"<<endl; }
    };
    class V1:public B1{
        public:
        V1(){ cout<<"Constructor:V1()"<<endl; }
    };
    class D1:virtual public V1{
        public:
        D1(){ cout<<"Constructor:D1()"<<endl; }
    };

    class B2{
        public:
        B2(){ cout<<"Constructor:B2()"<<endl; }
    };
    class B3{
        public:
        B3(){ cout<<"Constructor:B3()"<<endl; }
    };
    class V2:public B1,public B2{
        public:
        V2(){ cout<<"Constructor:V2()"<<endl; }
    };
    class D2:virtual public V2,public B3{
        public:
        D2(){ cout<<"Constructor:D2()"<<endl; }
    };
    class M1{
        public:
        M1(){ cout<<"Constructor:M1()"<<endl; }
    };
    class M2{
        public:
        M2(){ cout<<"Constructor:M2()"<<endl; }
    };
    class X:public D1,public D2{
        public:
        X(){ cout<<"Constructor:X()"<<endl; }                     
        M1 m1_;
        M2 m2_;
    };
    int main(){
        X x;
    }

    9. 访问权限的使用

     

    10. 类中隐式声明的函数

    11. C++中不同层次的内存分配情况

    12. new或malloc实际分配空间的大小

    如果想到内存对齐的情况,这个问题就很好解决了。

    内存对齐的情况要求实际得到的内存肯定不会小于要求分配的。一般都是高于这个值。

     

    13. STL中各容器额外的内存开销

     

    14. C++中new三种形式

     

    15. 类相关的new:与全局new是不同的

    简单new:plain new的重载

    定位new:placement new的重载

    nothrow new的重载

    16. 初始化陷阱

    注意在初始化的时候,不要搞成函数声明

     

    17. C++操作符上的贪婪匹配

    18. C++中的union

     

    19. 单片式设计陷阱

     

     

  • 相关阅读:
    Visual Studio使用阿里云Code Git服务器的常见问题
    使用Quartz.net来执行定时任务
    DirectorySearcher.Filter 属性(转)
    angular2的ElementRef在组件中获取不到
    angular2 ngfor循环
    angular2 日期格式化
    angular2在模板中使用属性引发Cannot read property 'xxx' of undefined
    Java ConcurrentHashMap存入引用对象时也是线程安全的
    FtpHelper实现ftp服务器文件读写操作(C#)
    Window服务项目脚手架
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2645568.html
Copyright © 2020-2023  润新知