C++语言执行标准

C++标准

1. C++标准简介

The document specifies requirements for implementations of the C++ programming language.

美国国家标准局(American National Standards Institute, ANSI) 在1990年设立了一个委员会(ANSI X3J16),专门负责制定C++标准(ANSI制定了C 语言标准)。国际标准化组织(the International Organization for Standardization, ISO) 很快通过自己的委员会(ISO-MG-21) 加入了这个行列,创建了联合组织 ANSI/ISO,致力于制定C+标准。

第一版,国际标准 ISO/IEC 14882:1998,于 1998 年获得 ISO、IEC(the International Electrotechnical Commission, 国际电工技术委员会) 和ANSI的批准。该标准常被称为C++98,它不仅描述了已有的 C++特性,还扩展了C++、添加了异常、运行阶段类型识别(RTTI)、模板和标准模板库(STL)。

第二版,ISO/IEC 14882:2003,对C++98的技术性修订,主要修订错误,减少多义性,没有改变语言特性,该版本称为C++03.

第三版,ISO/IEC 14882:2011,2011年9月11日正式发布,增加了许多新的语言特性。该版本称为C++11,还曾被称为C++ 0x,x曾预期为7或8.

第四版,ISO/IEC 14882:2014,在11基础上进行细微的完善和改进,该版本称为C++14. 包括:允许二进制字面量int var = 0b110; '0b'或 '0B'开头,但只能用来表示整型。

第五版,ISO/IEC 14882:2017,增加了一些特性,如允许命名空间嵌套定义,用新语法来定义函数的异常规格,引入新语法-推断指引(Deduction Guildes)等。该版本称为C++17.

第六版,ISO/IEC 14882:2020,2020年12月发布。官方文档ISO/IEC 14882:2020(en), Programming languages — C++.

第七版,ISO/IEC DIS 14882,正在开发中。ISO官网 https://www.iso.org/standard/83626.html

扩展:c++14新增语法和标准库特性_-飞鹤-CSDN博客

2. C++11新特性

  1. 统一的列表初始化方式。扩大了列表初始化的适用范围,使其可用于所有内置类型和用户定义的类型(类的对象)。并且,使用初始化列表时,可添加等号”=”,也不省略。

    int x1 = {5}; int x2 {55};
    short nums[3] {1,2,3};
    

    列表初始化禁止缩窄变换,即一个较大的数放进一个较小类型的变量里,但允许较窄类型的数放进较宽类型的变量里。

    类对象也可使用列表初始化。若类的某个构造函数接收模板类initializer_list作为函数的参数,则初始化列表语法只能用于该构造函数。

  2. 关键字声明

    auto以前是一个存储类型说明符,动态存储,C++11将其用于自动类型推断,必须进行显式初始化。

    decltype根据表达式类型定义变量类型。在使用模板函数时很方便,推导变量类型。

    decltype(x*n) y; // y的类型是x*n表达式的类型。
    
  3. 函数的返回类型后置

    double f1(double, int);
    auto f1(double, int) –> double;
    
  4. 此前,typedef可用于给数据类型起别名,现增加一种创建别名的语法 using = :

    using itType = vector<string>:: iterator;
    

    using 还可用于给模板类起别名,如vector、array等。

  5. nullptr空指针

    空指针是不会指向有效数据的指针。此前,使用0来表示该指针,但和整型的0冲突。C++11新增nullptr表示空指针,是指针类型,不可转换为整型。仍允许使用0来表示空指针,为向后兼容,因此nullptr==0 为true。

  6. 智能指针

    new的内存需要程序员显式delete释放,旧版本提供auto_ptr来自动完成该过程,但C++11废弃auto_ptr,新增3种智能指针unique_ptr,shared_ptr,weak_ptr。

    auto_ptr,unique_ptr,shared_ptr相当于对象,当指针的生命周期到时时,(在局部函数里,函数调用结束,栈释放,auto_ptr等自然不复存在),指针的析构函数将使用delete来释放所指向的内存空间。

    auto_ptr<int> pt (new int);
    

    #include <memory>,智能指针模板位于名称空间std中。

    智能指针定义时当作对象,使用时当作普通指针即可。由于智能指针会自动释放堆内存,要严格注意指针间赋值操作。但普通指针不需要有这种困扰。

    unique_ptr采用所有权模型,在一个作用域内,只能有一个指针指向同一块堆内存,unique_ptr在编译期检错;auto_ptr采用所有权模型,在运行期检错;shared_ptr,采用引用计数,允许多个指针指向同一块堆内存。

  7. 作用域内的枚举enum

    以前,同一作用域中不同枚举类型的成员不能重名。由于不同的实现可以选择不同的底层类型,因此枚举可能不能完全移植。C++新增枚举声明,添加class或struct定义。

    enum class color {red, yellow, blue};
    

    引用特定枚举值需要显式使用限定符,如New1::never, New2::never.

  8. C++11允许类定义里初始化成员变量,但构造函数里对成员变量的修改会覆盖初始化的值。

    构造函数被继承和彼此调用

    管理虚方法virtual:以前,如果子类的同名函数

  9. 右值引用

    传统的引用可关联左值,左值可出现在赋值语句的左边,可获取地址。但const常量可获取地址,但不能赋值。

    const int b = 0;
    const int & rb = b; // 引用前必须也加const
    

    C++11新增右值引用,用&&表示,右值是可以出现在”=”右边,但不能对其应用地址运算符的值,包括字面常量(C风格字符串除外,它表示地址)、表达式、返回类型为数值类型的函数。

    int && rt = 13; // 相当于int rt = 13; rt可以获取地址。改变值。
    

    引入右值引用的主要目的是实现移动语义

  10. 移动语义允许将1个对象的资源所有权从自己转移到另一个对象,而不需进行昂贵的复制操作。std::move(),如unique_ptr智能指针。

    拷贝构造函数:创建新对象,分配内存和复制数据

    移动构造函数:使用右值引用来接收1个临时对象或1个即将被销毁的对象,将其资源所有权转移到新对象中。只涉及指针的复制。

  11. 模板类和标准模板库(STL, Standard Templates Library)

    C++11新增STL容器unordered_map, unordered_multimap, unordered_set, unordered_multiset, forward_list(单向链表,对比于双向链表list)。前4种使用哈希表实现。新增模板array(就是个数组array<int, 5>,定义之后长度不可变,因此没有push_back等方法)。

    对于内置数组,含有方法begin(), end()的类,如string,和STL容器,可使用for(auto/type x: container)循环,若要修改x的值,则使用引用for(auto/type &x: container)

    新增cbegin(), cend(),是begin(), end()的const版本,防止对原容器的元素进行误改等操作。

    begin(), end(), 分别指向容器的第一个元素,容器最后一个元素的后面。rbegin(), rend(), 分别指向容器的最后一个元素,容器第一个元素的前面,联合使用达到逆序遍历的效果。crbegin(), crend()是其const版本。

    旧版使用嵌套模板时,尖括号要用空格分开,防止与运算符”>>”混淆,vector<list<int> > vec;

    C++11不再要求,vector<list<int>> vec;

  12. 多线程

    新增 线程支持库<thread>, <mutex>, <condition_variable>和<future>

    新增 原子操作库

    关键字thread_local,静态存储,与每个线程绑定一个,持续性和绑定的线程一致。

  13. Lambda表达式/Lambda函数

    lambda函数也叫lambda表达式,就是匿名函数。C++11中,对于接收函数指针或函数符(STL中函数对象)作为参数的函数,可以使用lambda作为参数。

    lambda表达式定义的地方和调用的地方在同一个地方,便于调试和修改代码。通常lambda没有名字,也可给lambda指定名称。

    auto func = [] (int x) {return x % 3 == 0;}; // 给lambda指定名称func
    bool res = func(3);
    

    当lambda函数体只有一条语句时,如只有一条return,可不显式写返回类型,由decltype推断。否则,需要显式写返回类型,采用返回类型后置的格式,如下:

    [] (int x) –> int {x = 1; return x % 3;};
    

    lambda捕获方式主要有三种:值捕获、引用捕获和隐式捕获,使lambda函数体内可使用外部所有动态变量。有两种方式传入外部变量,一种是引用&,一种是值=,如果只传特定变量(显式捕获),则传值方式时可省略=(值捕获),传引用方式不可省略&(引用捕获)。传全部的外部变量时(隐式捕获),值方式用“=”标识所有变量,引用方式用“&”。捕获的变量放进 [] 里声明。

    [m,&n] (int x) –> int {x = m; return x % 3;}; // 值捕获:m传值,引用捕获:n传引用
    [=] (int x) –> int {x = n; return x % 3;}; // 隐式捕获:外部所有变量都通过值方式传递
    [&] (int x) –> int {x = n; return x % 3;}; // 隐式捕获:外部所有变量都通过引用方式传递
    [=,&n] (int x) –> int {x = n; return x % 3;}; // 表示n以引用方式传递,剩余变量以值方式传递
    // 隐式捕获与显式捕获混用时,隐式捕获必须是[]里第一个参数
    

    一些注意事项和详细例子:C++ lambda表达式详细讲解2-隐式捕获与显式捕获-bingma03的博客-CSDN博客

热门相关:倾心之恋:总裁的妻子   道君   锦乡里   变身蜘蛛侠   道君