在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
现在保留用于标准化。
定义
override
,final
,carries_dependency
或noreturn
为macros的有效C ++ 2003代码在C ++ 0x中无效。
auto关键字的含义改变了。
打破变化?
那么,首先,如果你使用decltype
, constexpr
, nullptr
等作为标识符,那么你可能会遇到麻烦…
“不兼容性”部分未涵盖的一些核心不兼容性:
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::B
在main
仍然不可访问。
显式转换操作符是如何引入突变的? 旧版本仍然会像以前一样“有效”。
是的,从operator void*() const
到explicit 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
的规则)转换为val
types的值。 该值存储在val
,ios_base::goodbit
存储在err
。- 阶段2中积累的字符序列会导致
scanf
报告input失败。ios_base::failbit
被分配给err
。 [编辑:没有存储在val
]
[C++11: 22.4.2.1.2/3]:
[..]要存储的数值可以是下列之一:
- 零,如果转换函数无法转换整个字段 。
ios_base::failbit
被分配给err
。- 如果该字段表示一个值太大的正值,则表示为
val
。ios_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
- 使用{}进行统一和常规初始化
- 汽车
- 预防缩小
- constexpr
- 基于循环的范围
- nullptr
- 枚举类
- static_assert
- 的std :: initializer_list
- 右值引用(移动语义)
-
>>
- Lambdaexpression式
- 可变模板
- types和模板别名
- Unicode字符
- 长整数types
- alignas和alignof
- decltype
- 原始string文字
- 广义POD
- 广义的工会
- 本地类作为模板参数
- 后缀返回types的语法
- [[carry_dependency]]和[[noreturn]]
- 不包括说明符
- 不接受操作员。
- C99特点:
- 扩展的整型
- 窄/宽串的连接
- _ _ STDC_HOSTED _ _
- _Pragma(X)
- 可变参数macros和空macros参数
- _ _ func _ _
- 内联命名空间
- 委托构造函数
- 类内成员初始值设定项
- 默认和删除
- 显式转换运算符
- 用户定义的文字
- 外部模板
- 函数模板的默认模板参数
- inheritance构造函数
- 重写和最终
- 更简单和更一般的SFINAE规则
- 内存模型
- thread_local
标准库组件
- 容器的initializer_list
- 移动容器的语义
- 修饰符Modifiers
- 散列容器
- unordered_map
- unordered_multimap
- unordered_set
- unordered_multiset
- 资源pipe理指针
- 的unique_ptr
- shared_ptr的
- 的weak_ptr
- 并发支持
- 线
- 互斥
- 锁
- 条件variables
- 更高级别的并发支持
- packaged_thread
- 未来
- 诺言
- asynchronous
- 元组
- 正则expression式
- 随机数字
- uniform_int_distribution
- normal_distribution
- random_engine
- 等等
- 整数types名称,如int16_t,uint32_t和int_fast64_t
- 排列
- 复制和重新抛出exception
- 系统错误
- 容器的emplace()操作
- constexpr函数
- 系统使用noexceptfunction
- function和绑定
- string到数值转换
- 范围分配器
- types特征
- 时间效用:持续时间和time_point
- 比
- quick_exit
- 更多的algorithm,例如move(),copy_if()和is_sorted()
- 垃圾收集ABI
- primefaces能
已弃用的function
- 使用析构函数生成复制构造函数和类的复制分配。
- 将string文字分配给char *。
- C ++ 98exception规范
- unexcepted_handler
- set_unexpected
- get_unexpected
- 意外
- function对象和相关function
- auto_ptr的
- 寄存器
- ++上一个布尔
- 出口
- C风格的演员