在C ++ 11中引入了什么突破性变化?

我知道至less有一个C ++ 11的变化会导致一些旧的代码停止编译:在标准库中引入explicit operator bool() ,replaceoperator void*()旧实例。 当然,这个会破坏的代码可能是代码本来不应该是有效的,但它仍然是一个突破性的变化:过去不再有效的程序。

有没有其他突破的变化?

FDIS有一个不兼容的部分,在附录C.2 “C ++和ISO C ++ 2003”中。

总结,在这里解释FDIS,使其(更好)适合作为SO答案。 我添加了一些我自己的例子来说明差异。

有一些与图书馆相关的不兼容性,我不完全知道其中的含义,所以我把这些留给别人去详细说明。

核心语言


 #define u8 "abc" const char *s = u8"def"; // Previously "abcdef", now "def" 

 #define _x "there" "hello"_x // now a user-defined-string-literal. Previously, expanded _x . 

新的关键字:alignas,alignof,char16_t,char32_t,constexpr,decltype,noexcept,nullptr,static_assert和thread_local


大于long的某些整数文字可能会从无符号整数types变为有符号长long。


使用整数除法的有效C ++ 2003代码将结果向0或向负无穷发送,而C ++ 0x总是将结果向0进行四舍五入。

(诚​​然,大多数人不是真正的兼容性问题)。


使用关键字auto作为存储类说明符的有效C ++ 2003代码在C ++ 0x中可能无效。


缩小转换会导致与C ++ 03不兼容。 例如,下面的代码在C ++ 2003中是有效的,但在这个国际标准中是无效的,因为double到int是一个缩小的转换:

 int x[] = { 2.0 }; 

隐式声明的特殊成员函数被定义为当隐式定义不合格时被删除。

一个有效的C ++ 2003程序,在不需要定义的情况下(例如,在未被潜在评估的expression式中),使用这些特殊成员函数之一会变得不合格。

我的例子:

 struct A { private: A(); }; struct B : A { }; int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ } 

这种尺寸的技巧已被一些SFINAE使用,现在需要改变:)


用户声明的析构函数有一个隐含的exception规范。

我的例子:

 struct A { ~A() { throw "foo"; } }; int main() { try { A a; } catch(...) { } } 

此代码调用terminate在C ++ 0x,但不在C ++ 03中。 因为C ++ 0x中A::~A noexcept(true)的隐式exception规范是noexcept(true)


包含export有效C ++ 2003声明在C ++ 0x中是export不正确的。


现在可以将一个有效的C ++ 2003expression式包含>紧接着另一个>作为closures两个模板。

在C ++ 03中, >>将始终是shift-operator令牌。


允许内部连接的函数的依赖调用。

我的例子:

 static void f(int) { } void f(long) { } template<typename T> void g(T t) { f(t); } int main() { g(0); } 

在C ++ 03中,这个调用f(long) ,但是在C ++ 0x中调用f(int) 。 应该注意的是,在C ++ 03和C ++ 0x中,以下调用f(B) (实例化上下文仍然只考虑了extern链接声明)。

 struct B { }; struct A : B { }; template<typename T> void g(T t) { f(t); } static void f(A) { } void f(B) { } int main() { A a; g(a); } 

没有采用更好的匹配f(A) ,因为它没有外部连接。


库变化

使用添加到C ++ 0x的C ++标准库中的任何标识符的有效C ++ 2003代码可能无法在本标准中编译或生成不同的结果。


包含新C ++ 0x标准库头名称的头文件的有效C ++ 2003代码在本标准中可能无效。


已经编译的期望交换的有效C ++ 2003代码可能不得不包含在<algorithm> <utility>


全局命名空间posix现在保留用于标准化。


定义overridefinalcarries_dependencynoreturn为macros的有效C ++ 2003代码在C ++ 0x中无效。

auto关键字的含义改变了。

打破变化?

那么,首先,如果你使用decltypeconstexprnullptr等作为标识符,那么你可能会遇到麻烦…

“不兼容性”部分未涵盖的一些核心不兼容性:


C ++ 0x将注入的类名作为模板,如果名称作为parameter passing给模板模板参数,并将其作为types传递给模板types参数。

如果dependency injection的类名始终是这些场景中的types,则有效的C ++代码可能会有不同的行为。 从我的叮当公关采取代码示例

 template<template<typename> class X> struct M { }; template<template<typename> class X> void g(int = 0); // #1 template<typename T> void g(long = 0); // #2 template<typename T> struct A { void f() { g<A>(); /* is ambiguous in C++0x */ g<A>(1); /* should choose #1 in C++0x */ } }; void h() { A<int> a; af(); } 

在C ++ 03中,代码同时调用第二个g


C ++ 0x使一些依赖于C ++ 03的名称现在是非依赖的。 并且要求名称查找非从属限定名称,这些名称引用当前类模板的成员,以在实例化时重复,并要求validation这些名称的查找方式与模板定义上下文中的相同。

取决于优势规则的有效C ++ 03代码现在不能再编译了,因为这种改变。

例:

 struct B { void f(); }; template<typename T> struct A : virtual B { void f(); }; template<typename T> struct C : virtual B, A<T> { void g() { this->f(); } }; int main() { C<int> c; cg(); } 

调用A<int>::f这个有效的C ++ 03代码在C ++ 0x中是无效的,因为实例化时的名字查找将会发现A<int>::f而不是B::f ,导致冲突与定义查找。

目前还不清楚FDIS是否是一个缺陷。 委员会知道这一点,并将评估情况。


一个使用声明,其中最后一部分与合格名称中限定符的最后部分中的标识符相同,表示基类,使用声明现在命名构造函数,而不是具有该名称的成员。

例:

 struct A { protected: int B; }; typedef AB; struct C : B { // inheriting constructor, instead of bringing A::B into scope using B::B; }; int main() { C c; cB = 0; } 

上面的示例代码在C ++ 03中格式良好,但在C ++ 0x中格式不正确,因为A::Bmain仍然不可访问。

显式转换操作符是如何引入突变的? 旧版本仍然会像以前一样“有效”。

是的,从operator void*() constexplicit operator bool() const改变将是一个重大的改变,但只有当它以错误的方式被使用时, 符合的代码不会被破坏。

现在,另一个重大改变就是禁止在聚合初始化时缩小转换范围 :

 int a[] = { 1.0 }; // error 

编辑 :只要记住, std::identity<T>将被删除在C ++ 0x (见注)。 这是一个方便的结构,使依赖types。 由于这个结构实际上并没有太多的function,所以应该修正它:

 template<class T> struct identity{ typedef T type; }; 

stream提取失败的处理方式不同。

 #include <sstream> #include <cassert> int main() { std::stringstream ss; ss << '!'; int x = -1; assert(!(ss >> x)); // C++03 and C++11 assert(x == -1); // C++03 assert(x == 0); // C++11 } 

更改提议

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23

标准参考

[C++03: 22.2.2.1.2/11]:第二阶段处理的结果可以是其中之一

  • 在阶段2中已经积累了一系列的字符(根据scanf的规则)转换为valtypes的值。 该值存储在valios_base::goodbit存储在err
  • 阶段2中积累的字符序列会导致scanf报告input失败。 ios_base::failbit被分配给err[编辑:没有存储在val ]

[C++11: 22.4.2.1.2/3]: [..]要存储的数值可以是下列之一:

  • 零,如果转换函数无法转换整个字段ios_base::failbit被分配给err
  • 如果该字段表示一个值太大的正值,则表示为valios_base::failbit被分配给err
  • 对于无符号整数types来说,如果该字段表示值太大而不能在val表示,则为负数可表示的值或零。 ios_base::failbit被分配给err
  • 转换的值,否则。

结果数值存储在val

实现

  • GCC 4.8 正确输出为C ++ 11 :

    声明`x == -1'失败

  • GCC 4.5-4.8 所有输出为C ++ 03以下,这似乎是一个错误:

    声明`x == -1'失败

  • Visual C ++ 2008 Express正确输出为C + + 03:

    断言失败:x == 0

  • Visual C ++ 2012 Express错误地为C ++ 11输出,这似乎是一个实现状态问题:

    断言失败:x == 0

容器库有很多改变,允许更高效的代码,但是在几个angular落的情况下默默地向后兼容。

例如,考虑一下std::vector ,默认构造,C ++ 0x和重大更改 。

关于隐式移动破坏了向后兼容性的讨论有很多

( 有关讨论的旧页面 )

如果你读到评论,隐含的移动回报也是一个突破性的变化。

 struct x { x(int) {} }; void f(auto x = 3) { } int main() { f(); } 

C ++ 03:有效。

C ++ 0x: error: parameter declared 'auto'

语言function

  1. 使用{}进行统一和常规初始化
  2. 汽车
  3. 预防缩小
  4. constexpr
  5. 基于循环的范围
  6. nullptr
  7. 枚举类
  8. static_assert
  9. 的std :: initializer_list
  10. 右值引用(移动语义)
  11. >>
  12. Lambdaexpression式
  13. 可变模板
  14. types和模板别名
  15. Unicode字符
  16. 长整数types
  17. alignas和alignof
  18. decltype
  19. 原始string文字
  20. 广义POD
  21. 广义的工会
  22. 本地类作为模板参数
  23. 后缀返回types的语法
  24. [[carry_dependency]]和[[noreturn]]
  25. 不包括说明符
  26. 不接受操作员。
  27. C99特点:
    • 扩展的整型
    • 窄/宽串的连接
    • _ _ STDC_HOSTED _ _
    • _Pragma(X)
    • 可变参数macros和空macros参数
  28. _ _ func _ _
  29. 内联命名空间
  30. 委托构造函数
  31. 类内成员初始值设定项
  32. 默认和删除
  33. 显式转换运算符
  34. 用户定义的文字
  35. 外部模板
  36. 函数模板的默认模板参数
  37. inheritance构造函数
  38. 重写和最终
  39. 更简单和更一般的SFINAE规则
  40. 内存模型
  41. thread_local

标准库组件

  1. 容器的initializer_list
  2. 移动容器的语义
  3. 修饰符Modifiers
  4. 散列容器
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. 资源pipe理指针
    • 的unique_ptr
    • shared_ptr的
    • 的weak_ptr
  6. 并发支持
    • 线
    • 互斥
    • 条件variables
  7. 更高级别的并发支持
    • packaged_thread
    • 未来
    • 诺言
    • asynchronous
  8. 元组
  9. 正则expression式
  10. 随机数字
    • uniform_int_distribution
    • normal_distribution
    • random_engine
    • 等等
  11. 整数types名称,如int16_t,uint32_t和int_fast64_t
  12. 排列
  13. 复制和重新抛出exception
  14. 系统错误
  15. 容器的emplace()操作
  16. constexpr函数
  17. 系统使用noexceptfunction
  18. function和绑定
  19. string到数值转换
  20. 范围分配器
  21. types特征
  22. 时间效用:持续时间和time_point
  23. quick_exit
  24. 更多的algorithm,例如move(),copy_if()和is_sorted()
  25. 垃圾收集ABI
  26. primefaces能

已弃用的function

  1. 使用析构函数生成复制构造函数和类的复制分配。
  2. 将string文字分配给char *。
  3. C ++ 98exception规范
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • 意外
  4. function对象和相关function
  5. auto_ptr的
  6. 寄存器
  7. ++上一个布尔
  8. 出口
  9. C风格的演员