关于c ++:C ++ 11中引入了哪些重大变化?

What breaking changes are introduced in C++11?

我知道C++ 11中至少有一个改变会导致一些旧代码停止编译:在标准库中引入EDCOX1 OR 0,替换EDCOX1 1的旧实例。当然,这将破坏的代码可能是一开始就不应该有效的代码,但是它仍然是一个破坏性的变化:以前有效的程序不再是。

还有其他突破性的变化吗?


FDIS有一个不兼容的部分,在附录EDCOX1,8,"C++和ISO C++ 2003"。

总结一下,在这里解释外国直接投资,使之(更好)适合作为一个这样的答案。我添加了一些自己的例子来说明不同之处。

有一些与库相关的不兼容性,我不清楚它的含义,所以我将这些留给其他人详细说明。

核心语言

1
2
#define u8"abc"
const char *s = u8"def"; // Previously"abcdef", now"def"
1
2
#define _x"there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .

New keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local

Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.

Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas C++0x always rounds the result toward 0.

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

Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in C++0x.

Narrowing conversions cause incompatibilities with C++03. For example, the following code is valid in C++ 2003 but invalid in this International Standard because double to int is a narrowing conversion:

1
int x[] = { 2.0 };

Implicitly-declared special member functions are de?ned as deleted when the implicit definition would have been ill-formed.

A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expresion that is not potentially evaluated) becomes ill-formed.

我的例子:

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

这种规模的技巧已经被一些sfinae使用,现在需要更改:)

User-declared destructors have an implicit exception specification.

我的例子:

1
2
3
4
5
struct A {
  ~A() { throw"foo"; }
};

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

此代码在C++ 0x中调用EDCOX1×9Ω,但不在C++ 03中调用。因为在C++ 0x中EDOCX1·10的隐含隐式规范是noexcept(true)

A valid C++ 2003 declaration containing export is ill-formed in C++0x.

A valid C++ 2003 expression containing > followed immediately by another > may now be treated as closing two templates.

在C++ 03中,EDCOX1×12的总是将是移位操作符令牌。

Allow dependent calls of functions with internal linkage.

我的例子:

1
2
3
4
5
6
7
static void f(int) { }
void f(long) { }

template<typename T>
void g(T t) { f(t); }

int main() { g(0); }

在C++ 03中,它调用EDCOX1 OR 13,但是在C++ 0x中,它调用EDCOX1×14Ω。应该注意的是,在C++ 03和C++ 0x中,下面调用EDCOX1(15):(实例化上下文仍然只考虑外部链接声明)。

1
2
3
4
5
6
7
8
9
10
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)

图书馆变革

Valid C++ 2003 code that uses any identifiers added to the C++ standard
library of C++0x may fail to compile or produce different results in This International Standard.

Valid C++ 2003 code that #includes headers with names of new C++0x standard library headers may be invalid in this International Standard.

Valid C++ 2003 code that has been compiled expecting swap to be in may have to instead include

The global namespace posix is now reserved for standardization.

Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in C++0x.


自动关键字的含义已更改。


打破改变?

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


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

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

如果依赖于注入的类名在这些场景中始终是一个类型,则有效C++ 03代码的行为可能会有所不同。示例代码取自我的clang pr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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中,代码调用第二个EDCOX1,0,这两个时间。

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

依赖于支配规则的有效C++ 03代码现在不能再编译了,因为这个改变。

例子:

1
2
3
4
5
6
7
8
9
10
11
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(); }

在C++ 0x中调用EDCOX1 OR 1的有效C++ 03代码无效,因为实例化时的名称查找会发现EDCOX1 1Ω,而不是EDCOX1 3Ω,导致AT定义查找冲突。

目前还不清楚这是否是外国直接投资的缺陷。委员会意识到这一点,并将对形势进行评估。

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

例子:

1
2
3
4
5
6
7
8
9
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中是不正确的,因为EDCOX1,4,在EDCOX1 5中仍然是不可访问的。


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

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
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]: The result of stage 2 processing can be one of

  • A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val. This value is stored in val and ios_base::goodbit is stored in err.
  • The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err. [ed: Nothing is stored in val.]

[C++11: 22.4.2.1.2/3]: [..] The numeric value to be stored can be one of:

  • zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
  • the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
  • the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
  • the converted value, otherwise.

The resultant numeric value is stored in val.

启动位置

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


    Assertion `x == -1' failed

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


    Assertion `x == -1' failed

  • Visual C++ 2008表示C++ 03的正确输出:


    Assertion failed: x == 0

  • Visual C++ 2012对C++ 11的输出表示不正确,这似乎是实现问题的一个状态:


    Assertion failed: x == 0


显式转换运算符的引入是如何一种突破性的变化?旧版本仍将像以前一样"有效"。

是的,从operator void*() constexplicit operator bool() const的变化将是一个突破性的变化,但前提是它的使用方式本身是错误的。一致性代码不会被破坏。

现在,另一个突破性的变化是在聚合初始化期间禁止收缩转换:

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

编辑:仅记住,EDCOX1,2将在C++0x中删除(见注释)。它是一个使类型依赖的便利结构。由于结构实际上不起多大作用,因此应该修复它:

1
2
3
4
template<class T>
struct identity{
  typedef T type;
};


对容器库进行了许多更改,这些更改允许更高效的代码,但会悄悄地破坏一些角情况的向后兼容性。

例如,考虑EDCOX1,7,默认构造,C++0x,和断裂变化。


关于隐式移动打破向后兼容性的讨论很多。

(有相关讨论的旧页)

如果您向下阅读注释,隐式移动返回也是一个突破性的更改。


1
2
3
4
5
6
7
8
9
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C++ 03:有效。

C++0x:EDCOX1〔6〕


语言功能

  • 使用进行统一和常规初始化
  • 汽车
  • 防止缩窄
  • 常量表达式
  • 基于范围的循环
  • 努尔普特
  • 枚举类
  • 静态断言
  • std::初始值设定项列表
  • 右值引用(移动语义)
  • >>
  • 兰姆达斯
  • 可变模板
  • 类型和模板别名
  • Unicode字符
  • 长整型
  • 对齐方式和对齐方式
  • 解密
  • 生字符串
  • 广义荚果
  • 广义联合
  • 作为模板参数的本地类
  • 后缀返回类型语法
  • [[携带依赖项]]和[[noreturn]]
  • NoExcept说明符
  • NoExcept运算符。
  • C99特征:
    • 扩展积分类型
    • 窄/宽字符串的串联
    • _托管的stdc___
    • λ(x)
    • vararg宏和空宏参数
  • FucC
  • 内联命名空间
  • 委托构造函数
  • 在类成员初始值设定项中
  • 默认和删除
  • 显式转换运算符
  • 用户定义数据标识
  • 外部模板
  • 函数模板的默认模板参数
  • 继承构造函数
  • 覆盖和最终
  • 更简单和更一般的斯芬纳规则
  • 记忆模型
  • 线程局部
  • 标准库组件

  • 容器的初始值设定项列表
  • 移动容器的语义
  • 转发列表
  • 散列容器
    • 无序映射
    • 无序的多重映射
    • 乱序集
    • 无序多集
  • 资源管理指针
    • 尤尼奎
    • SelddPPTR
    • 弱者PTR
  • 并发支持
    • 线
    • 互斥器
    • 条件变量
  • 更高级别的并发支持
    • 打包螺纹
    • 未来
    • 承诺
    • 异步的
  • 元组
  • 正则表达式
  • 随机数
    • 均匀分布
    • 正态分布
    • 随机引擎
    • 等。
  • 整数类型名称,如int16_t、uint32_t和int_fast64_t
  • 数组
  • 复制和重新引发异常
  • 系统误差
  • 容器的emplace()操作
  • constexpr函数
  • noexcept函数的系统使用
  • 功能和绑定
  • 字符串到数值的转换
  • 作用域分配器
  • 体型性状
  • 时间实用程序:持续时间和时间点
  • 比率
  • 快速退出
  • 其他算法,如move()、copy_if()和is_sorted()。
  • 垃圾收集ABI
  • 原子学
  • 不推荐使用的功能

  • 为具有析构函数的类生成复制构造函数和复制分配。
  • 将字符串文本赋给char*。
  • C++ 98异常规范
    • 无例外处理程序
    • 意外出局
    • 意想不到的
    • 想不到的
  • 函数对象和关联函数
  • 自动PTR
  • 登记
  • 布尔上的++
  • 出口
  • C型铸件