zoukankan      html  css  js  c++  java
  • 侯捷-C++2.0

    C++ 2.0的内容分为2部分讲解:

    一, 新的语法;

    二, 标准库中新的内容;

    一、 新的语法

    1. 声明一个类时,C++会默认生成big five成员函数。

    默认构造函数,默认析构函数,默认拷贝构造,默认赋值构造,默认移动构造(移动拷贝构造,移动赋值构造)。

    默认构造函数的作用:调用当前类的父类构造函数。

    默认拷贝构造函数的作用:将非静态的成员变量逐个进行复制。若成员变量中存在指针,执行的是浅拷贝。因此,定义一个新类时,若成员变量中村子指针,则需要重新定义big three函数(默认拷贝构造,默认赋值构造,默认析构),将浅拷贝改为深拷贝。

    2. 一般情况下,构造函数都是public权限。但是,若构造函数声明为private权限,则只有编译器有权限调用该构造函数,任何用户都无权限调用。

    3. 关键字 decltype

    作用:let the compiler find out the type of an expression.

    应用:a) 声明返回类型;b) 元编程; c) 获取lambda函数的类型;

    a)利用decltype提供一种返回类型的声明方法。

    template <typename T1, typename T2>

    auto add(T1 x, T2 y) -> decltype(x+y); 

    4. lambdas 函数

    lambdas函数可以视为函数对象(function object),其对应关系可以用如下两个例子展示。

    例子1

     例子2

    5. 可变模板

    变化的是模板参数。参数的数量和类型都会变化。

    利用参数个数逐一递减的特性,实现递归函数调用。

    可变模板例子 1)

    函数1是递归终止条件;

    函数2和函数3可以并存,但是编译器会优先使用更为特化的函数2;

    可变模板例子 3)

    利用可变模板实现取最大值的功能。

    右下角的代码,结构体 _Iter_less_iter,成员函数重载()。_Iter_less_iter(),是调用了默认构造函数?还是调用了重载函数()?

    侯捷介绍:_Iter_less_iter 重载了(),因此对象可以像函数一样被调用。

    可变模板例子 6)

    tuple的构造函数利用可变模板实现递归继承,从而完成tuple对象的初始化。

    构造函数中,在初始化列表中,调用父类构造函数 inherited(vtail...)。

    使用private继承,其目的在于仅仅使用父类对象的内存空间。

    存疑地方,typename的使用 typename Head::type head() { return m_head; }

    可变模板例子 7)

    利用可变模板实现tuple类型的对象初始化。递归复合的内存示意图如右上角所示,x<T1, T2, T3>中包含x<T2, T3> ,,,

    二、 标准库新的内容

    本节的教学目标:自己设计一个 move aware class,可以执行move操作。

    右值引用 rvalue references

    作用:右值引用可以优化一些不必要的拷贝操作,极大提升代码的效率。

    1) 临时对象就是一种右值;

    2) 右值只能出现在等号右边;

    编译器可以识别函数名为函数所在的内存地址起点,即函数所在的地址。

    注意:如下代码段中,foo为函数名;foo() 代表函数返回的东西,是一个右值,右值不可寻址。

     

    如下例子,通过右值引用避免拷贝操作。

    需要满足如下条件:

    1)调用端告诉编译器,这是一个右值。可以是临时对象 或者 使用std::move()将左值转换为右值;

    2)被调用端写出一个专门处理rvalue的移动赋值函数,例如 c.insert(..., &&x)。形参中的右值引用要求元素类型必须要有对应移动构造函数(与之相对应,拷贝构造函数都是深拷贝操作)。

    上图代码中, c,c1,c2都是 std::vector<MyString> 类型。

    其中 M c1(c); 执行深拷贝;  M c2(std::move(c1)); 执行vector中3个指针的交换(swap)。

    3个指针包括,vector的内存首指针,内存尾指针和数据尾指针。

    被调用端

    如图所示,G4.9 是 C++ 2.0。其中,vector.insert()添加了专门处理右值引用的版本(move aware)。

    C++ 2.0 中新版本的 vector.insert(..., && x) 要求vector中存储的元素要有move aware的构造函数,包括移动构造和移动赋值。这样的元素类型才能进行移动操作,节省拷贝操作。

    完美传递 和 不完美传递

    如下 forward(2);  和  forward(move(a)); 所示,输入右值参数,在forward() 函数内部调用proces() 函数时,却变成了左值。这是不完美的传递。

     

    C++2.0 提供完美传递 std::forward<>(),可以保持参数的特性,包括modifiable,const,lvalue 和 rvalue。

    设计一个move aware class, MyString。

    MyString 的成员中有指针。针对指针变量,移动构造相比拷贝构造节省了拷贝构造操作。

    拷贝构造函数执行深拷贝;移动构造函数执行浅拷贝,同时把临时对象的指针置为nullptr。

    在析构函数中,判断临时对象的指针 _data 是否为空?若不为空,则进行delete操作。

    标准库的数据结构

    红色方框标识出C++2.0新的数据结构

    hashtable 

    篮子的大小 A=53,是一个质数。一个元素,对应一个hash code,它在hash表中存放位置 p 的计算方法为:

    hash code % A = p

    举个例子,55 % 53 = 2.

    当元素数量大于篮子数量时,扩充篮子数量至 2A 左右(取2A附近的最近质数),然后重新计算每个元素在hashtable中的存储位置。

    在实际情况中,hashtable中存放的是对象。因此,要利用 hash function 计算每个对象相应的 hash code。

    如下所示,计算一些基本数据类型的 hash code。hash code的特点要够杂够乱够随机,可以避免在 hashtable 中存放的冲突。

     

    对于 hash<int>()(123) ,第一个小括号表示创建一个临时对象,是一个 function object。第二个小括号表示调用这个function object,其行为类似于调用函数,传入参数123.

    上述代码的底层实现原理如下,先创建一个泛化的 hash 结构体,再针对每一种基本数据类型进行特化。

     

    利用hash function计算字符串的hash code

  • 相关阅读:
    Android popupwindow 失去焦点或者点击空白区域时消失的解决方法
    九度 题目1394:五连击数组
    地市级地铁数据管理信息系统解决方式
    用位运算实现两个整数的加法运算
    Leaflet--建设移动设备友好的互动地图
    atitit.自适应设计悬浮图片的大小and 位置
    PIM-DM协议内核触发机制及协议执行机制记录
    整合struts2+spring+hibernate
    UITableViewCell的prepareForReuse方法
    《linux 内核全然剖析》编译linux 0.12 内核 Ubuntu 64bits 环境
  • 原文地址:https://www.cnblogs.com/gdut-gordon/p/12228897.html
Copyright © 2011-2022 走看看