• [GeekBand] C++11~14


    一、关键字decltype

    由对象得到对象的数据类型,例如

    1. Complex  a(1,  2);    
    2. decltype(a)  b(3,  4);    

      declare type是让编译器去找到它的类型。

      Decltype甚至允许你使用在函数被调用时才确定的数据类型,例如:

    3. template  <  class  T1,  class  T2  > decltype(x  +  y)  add(T1  x.T2  y);    

      则等价于新引入的->语法(与lambda表达式的语法相似)

    4. template   <   class   T1,   class   T2   > auto  add(T1  x,  T2  y)  -   >  decltype(x  +  y);    

      二、哈希容器

      在C++11之前,存在hash_set,hash_multiset,hash_map,hash_multimap这几种基于哈希表的快速查找的容器;在C++11之后,hash统一更改为unordered.

      unordered_set的接口为:

      template < typename T, typename Hash = hash < T > , typename EqPred = equal_to < T > , typename Allocator = allocator < T >> class unordered_set;  

      比普通版本的容器多了这两类操作:

      第一类是总的hash表大小相关的函数:

      bucket_count(),max_bucket_count(),bucket_size(),bucket(const key_type& k)[返回k的bucket的下标];

      第二类是和占空比相关的函数:

      load_factor(),max_load_factor()/max_load_factor ( float z )[无参为取得最大占空比,有参未设置最大占空比],rehash ( size_type n )[改变大小为n并重新哈希],reserve ( size_type n )[改变大小为最适合装n个元素的哈希表并重新哈希];

      (一)用法

       

      三、lambda表达式

      C++11 lambda 表达式规范如下:

      [ capture ] ( params ) mutable exception attribute -> ret { body }

      (1)

         

      [ capture ] ( params ) -> ret { body }

      (2)

         

      [ capture ] ( params ) { body }

      (3)

         

      [ capture ] { body }

      (4)

         

      其中

    • (1) 是完整的 lambda 表达式形式,
    • (2) const 类型的 lambda 表达式,该类型的表达式不能更改捕获("capture")列表中的值。
    • (3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
      • 如果 lambda 代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。
      • 如果没有 return 语句,则类似 void f(...) 函数。
      • 此种形式最为常用。
    • 省略了参数列表,类似于无参函数 f()

    mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。

    exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X, Y)

    attribute 用来声明属性。

    另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表(也就是不需传参数直接就能看到的量),具体解释如下:

    • [a,&b] a变量以值的方式捕获,b以引用的方式被捕获。
    • [this] 以值的方式捕获 this 指针。
    • [&] 以引用的方式捕获所有的外部自动变量。
    • [=] 以值的方式捕获所有的外部自动变量。
    • [] 不捕获外部的任何变量。

    此外,params 指定 lambda 表达式的参数。

    四、右值引用与搬移语义

    目的:减少不必要的Copy。很多Copy是在我们不注意的情况下产生的,比如生成一个临时对象并放到容器去的时候,就涉及了一个拷贝,例如c.insert(string("123"))。

    • 左值指的是"可以"出现在=左边的东西;右值指的是"只能"出现=在右边的东西。

    通常来讲,没有名称的东西都是右值,最常用的是临时对象(包括中间运算结果)。但是在C++11中,我们可以写出这样的代码

    1. string  s1,  s2;    
    2. string()  =  "World";    
    3. s1  +  s2  =  s2;    

      这其实是很奇怪的,右值竟然出现在左边并通过了编译。

      所谓的右值引用,是指让左边可以"窃取"到右边的资源,而不需要先拷贝右边,再将右边析构。

      以vector::insert()为例,现在它有了insert(…… &x)和insert(…… &&x)两种定义。当我们如果使用了vector<myClass>.insert(myClass(1,2))时,就会调用到insert(…… &&x)的这个版本,这个版本内部会调用一个右值引用版本的拷贝构造函数,其接口为:

      myClass(myClass&& rvalue) noexcept;//这里必须有无异常声明。

      其行为仅仅是一个浅拷贝,这就要求原来的rvalue不能继续被使用,否则就会发生两个对象共享一个实例的情况。

      对于临时对象来说,这一点一定得以保证;

      如果对于其他对象,我们如果可以通过移动语义:

    4. myClass  a;  //生成对象a     
    5. myClass(std::move(a))  b;  //利用移动语义的拷贝构造函数,是一个浅复制,执行完之后a不再可用。    

      move的语义可以理解为,强行将一个左值变成右值;右值的特点是,会调用右值引用版本的拷贝构造和赋值函数。这两种函数应该通过浅复制实现来减少不必要的copy,也就是说:

      如果b=move(a),则会变为b<->a,发生交换(采用交换而不是只管b的原因是必须让a不再为a,不然会出现共享实例);

      对于myClass(std::move(a)),则是变为"临时对象"<->a,则a充当了临时对象的角色,而a的内容直接变成了目前的这个临时对象的内容(也就是空的东西)(这是一个浅复制)。

      那么现在一个关键的问题就是,这种浅拷贝版本的构造函数myClass(myClass&& rvalue) noexcept的实现到底怎么写?

      首先我们必须要理解,作为myClass&& rvalue形式接受进来的参数是什么的问题。对于myClass这一函数内部,rvalue其实是一个左值,myClass&&只代表接受参数的方式,在传参之后,rvalue就是一个普通有名变量,也就是通常意义上的左值【这一点,对于普通的引用传参也是一样的。可以类比,对于子函数,如果以引用形式接受参数,在子函数域内新的实参就是普通变量,和我采用了引用传递还是值传递没有什么关系】

      在移动语义版本中,我们不再需要为指针变量分配新的空间,只需要:1.利用原对象对非指针变量进行初始化;2.简单改变指针指向;3.使原指针变为空指针。这一步是必须的,否则由于内存回收时调用析构函数会把原地址空间释放掉。并且,在析构的时候必须检查是否是空指针在进行delete,否则会发生内存泄露。

      五、 容器

      一、 Array容器类型

      就是C++的数组的一个新包装。他的引入可以说就是为了使用数组时也可以使用容器的那些操作,是比较简单的一个容器。

      二、 emplace操作

      在C++11版本以后各个容器都引入了emplace的操作。

      Emplace的意思是,构造的同时进行插入:

    6. std::vector < Foo > v;  
    7. v.emplace(someIterator, 42, 3.1416); // 没有临时变量产生  
    8. v.insert(someIterator, Foo(42, 3.1416)); // 需要产生一个临时变量  
    9. v.insert(someIterator, {  
    10.     42, 3.1416  
    11. }); // 需要产生一个临时变量  
  • 相关阅读:
    Awesome Adb——一份超全超详细的 ADB 用法大全
    adb devices unauthorized的解决办法
    Vim用法AAAAA
    Security arrangements for extended USB protocol stack of a USB host system
    六 Python基础 字符串和编码
    四 Python基础
    三 Python解释器
    二安装Python
    Python教程(一)Python简介
    Python基本语法[二]
  • 原文地址:https://www.cnblogs.com/shawnChi/p/5892497.html
Copyright © 2020-2023  润新知