在C ++ 14中引入了哪些更改可能会破坏用C ++ 11编写的程序?

介绍

随着C ++ 14 (也就是C ++ 1y )标准接近终结,程序员必须问自己后向兼容性问题和相关问题。


这个问题

在这个问题的答案中指出,标准有一个专门的附录修改之间的变化信息。

如果前面提到的附录中的这些潜在问题能够得到解释,或许可以借助与那里提到的有关的任何正式文件,这将是有益的。

  • 根据标准 :在C ++ 14中引入了哪些更改可能会破坏用C ++ 11编写的程序?

注意 :在这篇文章中,我认为一个“ 突变 ”是或者两者兼而有之;
1.当编译为C ++ 14时,会导致合法的C ++ 11格式不正确的变化;
2.编译为C ++ 14 ,vs C ++ 11时将改变运行时行为的更改。


C ++ 11C ++ 14 ,标准说什么?

标准草案( n3797 )有一个专门用于这种信息的部分,它描述了标准的一个修订与另一个修订之间的(潜在的突破)区别。

本文使用该部分[diff.cpp11]作为对可能影响为C ++ 11编写代码但编译为C ++ 14的更改进行半精细讨论的基础。


C.3.1]数字分隔符

数字分隔符被引入,使得人们可以以更可读的方式写入数字文字,并以更自然的方式将其分开。

 int x = 10000000; // (1) int y = 10'000'000; // (2), C++14 

很容易看出, (2)在上面的代码片段中比(1)更容易阅读,而两个初始值都具有相同的值。

关于这个特性的潜在问题是, 单引号总是表示C ++ 11中 字符的开始/结束,但在C ++ 14中单引号可以围绕字符文字或者使用以前面所示的方式(2)

示例代码段,在C ++ 11C ++ 14中都是合法的,但具有不同的行为。

 #define M(x, ...) __VA_ARGS__ int a[] = { M(1'2, 3'4, 5) }; // int a[] = { 5 }; <-- C++11 // int a[] = { 3'4, 5 }; <-- C++14 // ^-- semantically equivalent to `{ 34, 5 }` 

(注意:有关单引号作为数字分隔符的更多信息可以在n3781.pdf中find)


C.3.2]大小的重新分配

C ++ 14引入了声明operator delete的全局重载的机会,适合大小的释放 ,这在C ++ 11中是不可能的。

但是,标准还要求开发者不能只声明下面两个相关函数中的一个,它必须声明none两者 ; 这在[new.delete.single] p11中有说明

 void operator delete (void*) noexcept; void operator delete (void*, std::size_t) noexcept; // sized deallocation 

有关潜在问题的更多信息:

现有的重新定义全局未定版本的程序也不定义大小的版本。 当一个实现引入一个大小的版本时,replace将是不完整的,并且程序可能会调用由编程人员提供的分配器分配的对象上的实现提供的大小的释放器。

注意 :引用来自n3536 – C ++大小的取消分配

(注意:在Lawrence Crowl编写的标题为n3536-C ++ Sized Deallocation的论文中有更多的兴趣)


C.3.3] constexpr成员函数,不再隐含const

在C ++ 14中, constexpr有很多变化,但唯一会改变C ++ 11C ++ 14之间语义的变化是标记为constexpr成员函数的 不变性

这种变化的基本原理是允许constexpr 成员函数改变它所属的对象,这是由于constexpr的放松而允许的 。

 struct A { constexpr int func (); }; // struct A { constexpr int func () const; }; <-- C++11 // struct A { constexpr int func (); }; <-- C++14 

有关这一变化的推荐材料,以及为什么它足够重要,以引入潜在的代码破坏:

  • Andrzej的C ++博客 – “constexpr”函数不是“const”
  • open-std.org – constexpr成员函数和隐式const
  • open-std.org – 对constexpr函数放宽限制)

示例代码片段,在C ++ 11C ++ 14中都是合法的,但具有不同的行为

 struct Obj { constexpr int func (int) { return 1; } constexpr int func (float) const { return 2; } }; 
 Obj const a = {}; int const x = a.func (123); // int const x = 1; <-- C++11 // int const x = 2; <-- C++14 

C.3.4]去除std::gets

std::gets已被从标准库中删除 ,因为它被认为是危险的 。

这样做的含义当然是试图编译用C ++ 11编写的代码,在C ++ 14中使用这样的函数很可能只是编译失败。

(注意:有些编写代码的方法不会编译失败,而且具有不同的行为,这取决于从标准库中删除std::gets