C ++ 11中引入了哪些重大变化?

时间:2011-06-18 23:48:26

标签: c++ c++11

我知道至少有一个C ++ 11中的更改​​会导致一些旧代码停止编译:在标准库中引入explicit operator bool(),替换operator void*()的旧实例。当然,这将破坏的代码可能是首先不应该有效的代码,但它仍然是一个重大变化:过去不再有效的程序。

还有其他重大变化吗?

10 个答案:

答案 0 :(得分:175)

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的整数文字可以用无符号整数类型改为有符号长整数。


  

使用整数除法的有效C ++ 2003代码将结果舍入为0或向负无穷大,而C ++ 0x始终将结果舍入为0。

(对大多数人来说,这不是一个真正的兼容性问题)。


  

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


  

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

int x[] = { 2.0 };

  

当隐式定义形成错误时,隐式声明的特殊成员函数被定义为已删除。

     

在不需要定义的上下文中(例如,在无法评估的表达式中)使用这些特殊成员函数之一的有效C ++ 2003程序变得格式不正确。

我的例子:

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

一些SFINAE已经使用了这么大的技巧,现在需要改变:)


  

用户声明的析构函数具有隐式异常规范。

我的例子:

struct A {
  ~A() { throw "foo"; }
};

int main() { try { A a; } catch(...) { } }

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


  

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


  

包含>并且紧跟另一个>的有效C ++ 2003表达式现在可以被视为关闭两个模板。

在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)(实例化上下文仍然只考虑外部链接声明)。

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 ++标准的任何标识符的有效C ++ 2003代码   C ++ 0x库可能无法编译或在本国际标准中产生不同的结果。


  

有效的C ++ 2003代码,在此国际标准中,#includes标题包含新C ++ 0x标准库标题的名称可能无效。


  

编译的有效C ++ 2003代码期望交换位于<algorithm>可能必须包含<utility>


  

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


  

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

答案 1 :(得分:27)

auto关键字的含义已更改。

答案 2 :(得分:23)

突破变化?

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

答案 3 :(得分:22)

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


如果将名称作为参数传递给模板模板参数,则C ++ 0x会将注入的类名称视为模板,如果将其传递给模板类型参数,则将其视为类型。

如果有效的C ++ 03代码依赖于注入的类名在这些场景中始终是一种类型,则其行为可能会有所不同。示例代码taken from my clang PR

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;
  a.f();
}

在C ++ 03中,代码两次调用第二个g


C ++ 0x使得一些依赖于C ++ 03的名称现在变得不依赖。并且需要对非依赖的限定名称进行名称查找,这些名称引用当前类模板的成员以在实例化时重复,并且需要验证这些名称的查找方式与模板定义上下文中的相同。

由于此更改,依赖于优势规则的有效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; c.g(); }

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

目前尚不清楚这是否是FDIS的缺陷。委员会意识到这一点,并将对情况进行评估。


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

示例:

struct A { protected: int B; };
typedef A B;

struct C : B {
  // inheriting constructor, instead of bringing A::B into scope
  using B::B;
};

int main() { C c; c.B = 0; }

上面的示例代码在C ++ 03中格式正确,但在C ++ 0x中格式不正确,A::B中仍然无法访问main

答案 4 :(得分:14)

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

实施例

#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阶段处理的结果可以是

之一      
      
  • 在阶段2中累积了一系列字符,这些字符被转换(根据scanf的规则)到val类型的值。此值存储在val中,ios_base::goodbit存储在err
  • 中   
  • 第2阶段累积的字符序列会导致scanf报告输入失败。 ios_base::failbit被分配到err [ed:val中没有存储任何内容。]
  •   
     

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

     
      
  • 零,如果转换功能无法转换整个字段ios_base::failbit被分配到err
  •   
  • 最正可表示的值,如果该字段表示的值太大而无法在val中表示。 ios_base::failbit被分配到err
  •   
  • 无效的可表示值或无符号整数类型的零,如果该字段表示的值太大而无法在val中表示。 ios_base::failbit被分配到err
  •   
  • 转换后的值,否则。
  •   
     

结果数值存储在val

实现

  • GCC 4.8 correctly outputs for C++11

      

    断言`x == -1'失败

  • GCC 4.5-4.8 all output for C++03以下内容似乎是一个错误:

      

    断言`x == -1'失败

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

      

    断言失败:x == 0

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

      

    断言失败:x == 0

答案 5 :(得分:13)

如何引入显式转换运算符?旧版本仍将像以前一样“有效”。

是的,从operator void*() constexplicit operator bool() const的更改将是一个重大变化,但前提是它的使用方式本身就是错误的。符合规范的代码不会被破坏。

现在,另一个重大变化是the banning of narrowing conversions during aggregate initialization

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

修改:记住,std::identity<T> will be removed in C++0x(请参阅说明)。这是一种使类型依赖的便利结构。由于结构实际上没有做太多,这应该解决它:

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

答案 6 :(得分:8)

对容器库进行了大量更改,这些更改允许更高效的代码,但在几个极端情况下默默地向后兼容。

例如,考虑std::vector, default construction, C++0x, and breaking changes

答案 7 :(得分:7)

implicit move breaking backward compatibility

进行了大量讨论

an older page with relevant discussion

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

答案 8 :(得分:6)

struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03:有效。

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

答案 9 :(得分:-2)

语言功能

  1. 使用{}
  2. 进行统一和一般初始化
  3. 自动
  4. 防止缩小
  5. constexpr
  6. 基于循环的范围
  7. nullptr
  8. enum class
  9. static_assert
  10. 的std :: initializer_list
  11. Rvalue引用(移动语义)
  12. >>
  13. lambda表达式
  14. 可变参数模板
  15. 类型和模板别名
  16. Unicode字符
  17. long long integer type
  18. alignas and alignof
  19. decltype
  20. 原始字符串文字
  21. 广义POD
  22. 广义工会
  23. 本地类作为模板参数
  24. 后缀返回类型语法
  25. [[carry_dependency]]和[[noreturn]]
  26. noexcept specifier
  27. noexcept operator。
  28. C99功能:
    • 扩展积分类型
    • 连接窄/宽字符串
    • _ _ STDC_HOSTED _ _
    • _Pragma(X)
    • vararg宏和空宏参数
  29. _ _ func _ _
  30. 内联命名空间
  31. 委派构造函数
  32. 课堂成员初始化者
  33. 默认并删除
  34. 显式转换运算符
  35. 用户定义的文字
  36. 外部模板
  37. 功能模板的默认模板参数
  38. 继承构造函数
  39. 覆盖和最终
  40. 更简单,更通用的SFINAE规则
  41. 内存模型
  42. thread_local
  43. 标准库组件

    1. 容器的initializer_list
    2. 移动容器的语义
    3. 修饰符Modifiers
    4. 哈希容器
      • unordered_map
      • unordered_multimap
      • unordered_set
      • unordered_multiset
    5. 资源管理指针
      • 的unique_ptr
      • shared_ptr的
      • 的weak_ptr
    6. 并发支持
      • 螺纹
      • 互斥
      • 条件变量
    7. 更高级别的并发支持
      • packaged_thread
      • 将来
      • 异步
    8. 元组
    9. 正则表达式
    10. 随机数
      • uniform_int_distribution
      • normal_distribution
      • random_engine
    11. 整数类型名称,例如int16_t,uint32_t和int_fast64_t
    12. 阵列
    13. 复制和重新抛出异常
    14. SYSTEM_ERROR
    15. 容器的emplace()操作
    16. constexpr功能
    17. 系统使用noexcept功能
    18. function and bind
    19. 字符串到数值转换
    20. Scoped allocators
    21. 类型特征
    22. 时间效用:持续时间和时间点
    23. quick_exit
    24. 更多算法,例如move(),copy_if()和is_sorted()
    25. 垃圾收集ABI
    26. 原子学
    27. 弃用功能

      1. 为具有析构函数的类生成复制构造函数和复制赋值。
      2. 将字符串文字指定给char *。
      3. C ++ 98异常规范
        • unexcepted_handler
        • set_unexpected
        • get_unexpected
        • 意想不到
      4. 功能对象和相关功能
      5. 的auto_ptr
      6. 注册
      7. ++ on bool
      8. 出口
      9. C风格演员