Effective C++阅读笔记(03-14)

  • 条款03:多使用const

    • const与指针一起使用
      • 1. const在*左边 --> 被指向的是常量 const int * ptr1; int const * ptr2;
      • 2. const在*右边 --> 指针本身是一个常量,不可以指向其它地址 int * const ptr3;
    • STL中的迭代器就类似于T *
      • 迭代器 ---> T *
      • 将迭代器声明为const 即声明一个T * const(不能指向别的地址,但地址内的值可以修改)
      • 如需在STL中使用 const * T, 需要使用const_iterator(可以指向别的地址,地址内的值不可修改,只读作用)
    • const 作用于普通函数:
    • const成员函数(☞有 const 修饰的成员函数,指const 放在函数参数表的后面,而不是在函数前面或者参数表内,char get(int x,int y) const;)
      • 两个成员函数如果常量性不同,是可以被重载的.
      • const成员函数可以修改类的静态成员函数(static ), 原因为
        • 静态数据成员的定义不在类体内,在静态存储区。
        • 成员函数都会在自己的形参表中加一个参数:这个参数是指向函数所在类的类型的CONST指针
        • 上边的set函数,是给n赋值的,但是它怎么知道是给哪一个对象的n赋值呢?这就需要在参数中告诉它。编译器为我们作了这些工作。实际生成的set函数可以理解成这样的:
        • 而我们调用的时候其实是这样的:
        • 如果是const成员函数,编译器所作的这项工作也会改变。它会生成一个指向cosnt对象的const指针。所以你不能通过this来改变它所指向的对象。但是要知道static对象并不需要this指针来改变,所以它和const函数是没关系的。
      • 若将成员函数声明为const,则该函数内部不允许修改类的非静态数据成员(non-static)。例如:
      • 如果坚持在const成员函数内部修改成员变量,使用mutable关键字。
      • 当const 成员函数与non-const成员函数具有实质等价的实现时,使用non-const成员函数调用const成员函数可避免代码重复。不能使用const成员函数调用non-const成员函数,因为那样就可能会违背“const函数内部不允许修改类的非静态数据成员”的原则。(non-const成员函数没有这一原则)
  • 条款04:确定对象被使用前已先被初始化

    • 读取未初始化的值会导致不明确的行为。
    • 内置类型 --> 手动进行初始化 自定义类型 --> 构造函数进行初始化(确保每一个构造函数都将每一个成员初始化)
    • 不要混淆赋值(assignment)和初始化(initialization)!!!!!!!!
      • C++规定对象的成员变量的初始化动作发生在进入构造函数本体之前(对内置类型不一定成立)。
      • 构造函数的较优写法:使用成员初始列(member initialization list)替换赋值动作。如:
      • class A{ A( int id, string name, string adr) ; int id; string name; string adr ;}
      • A :: A( int id, string name, string adr) : id(id), name(name), adr(adr) {}
      • 为了避免“跨编译单元之初始化问题”,最好使用local static对象替换non-local static对象。
  • 条款05:了解C++默默编写并调用哪些函数

  • 条款06:若不想使用编译器自动产生的函数,就该明确拒绝

    • 为了拒绝编译器自动(暗自)提供的某种机能,可将相应函数声明为private且不予实现。使用Uncopyable这样的base class(基类)进行继承也是一种方法。
    • 将拷贝构造函数和拷贝操作符声明为private可以阻止赋值操作,但是友元函数和成员函数还是可以进行赋值操作。
    • 可以采用“继承”某个不能赋值拷贝的类来阻止member和friend的拷贝赋值操作。
  • 条款07:为多态基类声明virtual析构函数

  • 条款08:别让异常逃离析构函数

  • 条款09:绝不在构造和析构过程中调用virtu函数

    • dynamic_cast运算符的主要用途:将基类的指针或引用安全地转换成派生类的指针或引用。
    • 继承类对象中的基类成员会在继承类本身成员构造之前所调用,即基类构造函数发生在继承类构造函数之前。如果在基类构造函数内使用基类中的虚函数,此时“虚函数不是虚函数”。(无法下降到继承类版本,因为调用了基类版本的虚函数,违反了虚函数的父类指针指向子类对象的概念,所以“虚函数不是虚函数”)
    • explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式). 即被explicit关键字修饰的类构造函数,不能进行自动地隐式类型转换(例如 int a = 1.2 ),只能显式地进行类型转换( int a = (double)1.2 )。
    • 总之:
  • 条款10:令operator=返回一个reference to *this

    • 为了实现连续赋值等功能( int a = b = c = d = 10; ),类的operato=重载函数应该返回一个引用操作符的左侧实参。
  • 条款11:在operato=中处理“自我赋值”

    • 自我赋值 ——> int a = 0; a = a; arr[i] = arr[j]; //若i=j; *px = *py; //px与py指向同一地址
    • “自我赋值”是由别名带来的后果
  • 条款12:复制对象时勿忘其每一个成分

    • 为class添加一个变量时,需要同时修改copying函数。(包括构造函数以及非标准的operator=)
    • 为继承类撰写copying函数时,必须注意小心的复制基类的成员(这些成员往往是pricate,无法直接访问,需要在继承类的copying函数中调用基类中提供的函数接口)
  • 条款13:以对象管理资源

    • C++需要管理的资源包括:动态内存分配,文件描述器,互斥锁,图形界面中的字型和笔刷,数据库连接,网络sockets。
    • 利用C++类的“析构函数自动调用机制”确保资源被释放。
    • 标准程序库提供的auto_ptr在构造对象的时候获取资源,在析构的时候释放其所指的资源
    • 如果类有2个成员变量,指向两个资源,在构造函数中申请资源A成功,但申请资源B失败,则构造函数失败,那么析构函数不会被调用,那么资源A则泄漏。
    • 为了解决这个问题,我们可以利用auto_ptr取代普通指针作为成员变量,这样首先调用成功的成员变量的构造函数肯定会调用其析构函数,那么就可以避免资源泄漏问题。
    • 由于auto_ptr销毁时会自动删除所指内容,所以不能让两个auto_ptr指向同一对象;当使用auto_ptr的拷贝构造函数和operator=时,新的auto_ptr会指向这块地址(唯一拥有权),原有的auto_ptr会变成null;
    • 类似于auto_ptr智能指针,Share_ptr也是一种智能指针。Shared_ptr和auto_ptr最大的区别就是,shared_ptr解决了指针间共享对象所有权的问题,也就是auto_ptr中的赋值的“唯一所有权”的问题。多个shared_ptr可以指向同一份资源,所以满足了容器的要求,可以用于容器中。而auto_ptr显然禁止共享对象所有权,不可以用于容器中。
    • 获得资源后立即放入管理对象内
    • 管理对象运用虚构函数确保资源被释放
  • 条款14:在资源管理中小心copying行为

  • 条款15:在资源管理类中提供对原始资源的访问
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值