effective c++笔记

来源:互联网 发布:网络屏蔽机柜 编辑:程序博客网 时间:2024/05/24 01:50
  • 为什么尽量使用const,enum,而不使用define?

除了我们所知的类型检查问题之外,define是全局的,没有私有的概念,不能控制作用范围

  • 多个编译单元(一般就是多个源文件)non-local static变量的初始化顺序无法保证?

所谓non-local static就是指不在函数体内(函数内的变量是local变量)的全局变量,静态变量,他的初始化顺序编译器是不保证的,那么如果这些变量之间的调用有先后关系就可能出问题。那么如何解决这个问题的,一个小技巧就是把non-local static变为localstatic,就是把变量放到一个函数内,然后以函数的形式调用,这样c++编译器会保证函数体内的变量在第一次被使用的时候定义。

  • 不要在构造函数或者析构函数中调用virtual函数
    比如我们定义一个派生类对象,构造函数会先调用基类的构造函数,这个时候编译器是把这个对象当作基类的类型的(用typeid输出也会得到相同的结果),那么如果里面调用了虚函数,其实是调用了基类的函数,而不是子类的函数,从而违背了我们使用的初衷。因为基类构造函数调用的时候,子类的成员还没有被构造,如果c++把他当作子类的类型而允许调用子类的函数的话会发生不可预见的结果,所以禁止这么做。

  • operator=一定要注意自己给自己赋值的情况
    一个类
    class testop
    {
    public:
    testop& operator=(testop& tp)
    {
    if(m_pName != NULL)
    {
    delete m_pName;
    }
    m_pName = new char(strlen(tp.m_Name)+1);
    strcpy(this->m_pName,tp.m_Name );
    return *this;
    }
    ..
    private:
    char * m_pName;
    };
    如果自己给自己赋值的时候,delete m_pName;的时候就把自己的空间给释放掉了,还赋值什么啊。

  • 关于inline
    inline看起来很美好,有函数的类型检查,又没有函数调用带来的开销,单inline只能是一种申请,编译器不一定会真的执行,这和编译器的实现有关,但一般的编译器对于有循环、虚函数等复杂的函数是不会定义为inline的,即便编译器真的把一个函数定义为inline了,但如果我们用了函数指针指向这个函数,那么编译器除了inline部分还会定义一个普通的函数体(因为只有普通的函数才有地址),然后对于普通的调用是inline的,但如果是通过函数指针的却是普通函数。
    另外inline也会带来一些坏处:1)代码膨胀就不必多说了;2)如果inline函数被多个文件的函数调用,那么一点函数修改,所有调用的文件都要重新编译(因为inline是直接代码替换,相当于把调用的地方的代码修改了),而如果是普通函数修改,调用的文件只需要重新链接就好了

  • 模板
    模板里面的class 和 typename 含义基本是一样的,但typename还有另外的用处,我们称依赖模板参数的名称为嵌套从属名称,比如我们定义一个模板函数
    template void testfunc(const T& contain)
    {
    T::iterator * it;

    }
    这里面的itertor就是一个从属名称,因为它是依赖于T的,我们理所当然的任务iterator就是一个类型,但如果它不是一个类型呢,而是一个T里面的变量,那么含义就会变成 两个变量相乘,c++编译器为了规避歧义,就规定遇到一个嵌套从属名称默认是一个变量而不是类型,那么如果我们想让它是一个类型就可以在前面加上typename,比如 typename T::iterator *it; 这样就是iterator就是一个名称了。但是注意:不能在继承时基类的列表(比如 template class CDrived::public CBase::Nested,这里的CBase::Nested前面不能加typename)或成员初始化列表内(比如CDrived(int x):: CBase::Nested(x),这里的CBase::Nested前面不能加typename)以它作为base class的修饰符

0 0
原创粉丝点击