zoukankan      html  css  js  c++  java
  • [More Effective C++ 学习笔记]基础议题和操作符

    <基础议题>

           pointer和reference在继承机制下存在两种型别:

    1. 静态型别是指其声明时的型别;
    2. 动态型别是指它们实际所指的对象来决定。

      条款1:仔细区分pointer和references

      没有null references,一个reference必须总是代表某个对象。

      使用reference之前不需测试其有效性。若使用pointer,通常就是测试它是否为null。

      pointers和references的差异

    1. pointers可以被重新赋值,指向另一个对象;
    2. reference却总是指向(代表)它最初获得的那个对象,即使被重新赋值改变的也是原对象的值。

      operator[]返回某种能够被当做assignment赋值对象,则令operator[]返回一个reference。

      条款2:最好使用C++转型操作符

      static_cast:用于强制类型专函,不涉及继承机制的型别执行类型转换;

      const_cast:用来改变表达式中的常量性(constant)或易变性(volatileness);

      dynamic_cast:用来执行继承机制中安全的向下型别或跨系型别转换动作,即base objects->derived objects。若转换失败,返回null指针(转型对象是指针)或exception(转型对象是reference);

      reinterpret_cast:用户函数指针型别转换。

      条款3:绝对不要以多台(polymorphically)方式来处理数组

      继承性质之一:通过指向其基类对象的指针或引用,来操作继承基类的对象。

      数组声明时,向系统申请 numElemt * sizeof(数组中对象类型)大小的内存。而声名类类型对象时,系统给予对象类类型中数据数据大小的内存。类成员函数最终将转换成全局函数。数组中元素移动一位的内存距离是sizeof(数组对象的类型)。

      条款4:非必要不提供default constructor

      classes类缺乏default constructor在两种情况下出现问题:

    1. 产生数组时,系统调用默认构造函数;
    2. 不适用于许多template-based constainer classes。

      <操作符>

      条款5:对定制的型别转换函数保持警觉

      两种函数允许编译器进行隐式转换:单变量constructor和隐式型别转换操作符。其中,单变量constructors是指能以单一自变量成功调用的constructors。隐式型别转换操作符是指关键词operator之后加上一个型别名称。不需指定返回值类型,因为其返回值型别基本上已经表现于函数名称上。

      根本问题:在你从未打算也未预期的情况下,此类函数可能被调用,而其结果可能是不正确、不直观的程序行为,很难调试。

           关于隐式型别转换操作符的解决方法:以功能对等的另一个函数取代型别转换操作符。而单自变量constructors的解决方法之一:利用关键字explicit。若将constructors声明为explicit,编译器便不能因隐式型别转换的需要而调用它们。

           条款6:区别increment/decrement操作符的前置(prefix)和后置(postfix)形式

           在重载操作符increment/decrement时,为了区分前置式和后置式,让后置式有一个int自变量类型,但没有变量名称,如operator++(int);。在调用后置式时,编译器默默地为该int指定一个0值。

           自增和自减操作符的前置式和后置式返回不同的型别:前置式返回一个reference,后置式返回一个const对象。

      为什么后置式返回一个const对象?(设计classes的一条无上宝典就是:一旦有疑惑,试看ints行为如何并遵守之。)是为了防止如下行为的出现:

      int i = 4;

      i++++;  // 错误,但++++i合法

      条款7:千万不要重载&&,||和,操作符

      C++对于真假表达式采用所谓骤死式(即短路求值)评估方式,其含义是一旦该表达式的真假值确定,纵使表达式中还有部分尚未检验,整个评估工作仍然结束。

      条款8:了解各种不同意义的new和delete

      string *ps = new string(“Memory Management”);

      这里使用的new operator是由语言内建的,它总是做下面的两件事,无论如何你不能改变其行为。它的动作分为两方面:

    1. 它分配足够的内存,用于放置某型别的对象;
    2. 它调用constructor,为刚刚分配的内存中的那个对象设置初值。

      operator new表达式

      new operator调用函数operator new执行必要的内存分配动作,你可以在类中重载该函数。函数operator new通常声明为:

      void* operator new(size_t size);

      operator new只负责内存分配,而new operator的责任就是将operator new返回的内存转换为一个对象。

      表达式:string *ps = new string(“Memory Management”);编译器为该语句产生一些代码:

      void *memory = operator new (sizeof (string));   // get raw memory

      call string::string(“Memory Management”) on *memory // initialize objects

      string *ps = static_cast<string *>(memory);              // ps point the new object

      placement new表达式

      placement new表达式是指对一个已存在的内存缓冲区上构筑对象。

           例如:

           

    1 Widget *constructWidgetInBuffer(void *buffer, in widgetSize)
    2 {
    3 
    4     return new(buffer) Widget(widgetSize);
    5 
    6 }

           该函数返回指针,指向一个Widget object,它被构造于传递给此函数的一块内存缓冲区上。因此,placement new的operator new函数如下所示:

           

    1 void * operator new(size_t, void *location)
    2 {
    3     return location;
    4 }

           在函数中没有用到size_t参数,之所以不赋予名称,为的是避免编译器发出错误。

           删除(delete)与内存归还(Deallocation)

           函数operator delete之于内奸的delete operator,就好像operator new之于new operator一样。内存释放动作是函数operator delete执行,通常声明如下:

           void operator delete(void *memoryToBeDeallocation);

           因此,

           delete ps;

           在编译器转换之后:

           ps->~string();               // 调用对象的析构函数

           operator delete(ps);        // 释放对象所占用的内存

           但是需要注意的是,placement new是从已存在的内存区域中构筑对象。因此不能直接调用operator delete来释放该函数申请的内存。因此,调用析构函数函数来析构对象,然后将内存返还回去。

           数组的new和delete

           在给数组分配内存时,new operator 调用operator new[],而delete operator调用operator delete[]。

  • 相关阅读:
    BootstrapValidator验证规则、BootStrap表格:列参数
    使用JSONObject解析和生成json
    java.Math类常用方法
    Java内存溢出处理
    windows下Ubuntu虚拟机联网配置 + Ubuntu虚拟机代理配置
    C# 获取并判断操作系统版本,解决Win10、 Windows Server 2012 R2 读取失败的方案
    C++ 获取并判断操作系统版本,解决Win10、 Windows Server 2012 R2 读取失败的方案
    asp.net 程序,当发生找不到文件的错误时,如何正确定位是哪个文件?
    MVC 网站部署常见问题汇总
    ASP.NET windows验证IIS配置
  • 原文地址:https://www.cnblogs.com/life91/p/3002504.html
Copyright © 2011-2022 走看看