提问人:Filip Roséen - refp 提问时间:6/1/2014 最后编辑:Jean-François FabreFilip Roséen - refp 更新时间:7/8/2023 访问量:51758
C++14 中引入的哪些更改可能会破坏用 C++11 编写的程序?
What changes introduced in C++14 can potentially break a program written in C++11?
问:
介绍
使用 C++14(又名。C++1y)标准在接近最终状态时,程序员必须问自己向后兼容性,以及与此相关的问题。
问题
在对这个问题的回答中指出,该标准有一个附录,专门用于有关修订之间变化的信息。
如果能够解释前面提到的附录中的这些潜在问题,也许可以借助与附录中提到的内容相关的任何正式文件,那将是有帮助的。
- 根据标准:C++14 中引入的哪些更改可能会破坏用 C++11 编写的程序?
答:
注意:在这篇文章中,我认为“重大变更”是其中之一,或者两者兼而有之;
1. 在编译为 C++14 时会使合法的 C++11 格式不正确的更改;
2. 与 C++11 相比,将更改编译为 C++14 时的运行时行为。
C++11 vs C++14,标准怎么说?
标准草案 (n3797) 有一节专门用于此类信息,其中描述了标准的一个修订版与另一个修订版之间的(可能具有破坏性的)差异。
这篇文章使用该部分作为基础,对可能影响为 C++11 编写但编译为 C++14 的代码的更改进行了半详细的讨论。[diff.cpp11]
C.3.1] 数字分隔符
引入数字分隔符是为了以更易读的方式编写数字文字并编写我们通常(在代码之外)的文字。
int x = 10000000; // (1)
int y = 10'000'000; // (2), C++14
很容易看出,在上面的代码片段中,(2) 比 (1) 更容易阅读,而两个初始值设定项具有相同的值。
关于此功能的潜在问题是,在 C++11 中,单引号始终表示字符文字的开始/结束,但在 C++14 中,单引号可以放在字符文字周围,也可以以前面显示的方式使用 (2)。
示例代码段,在 C++11 和 C++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 )
C.3.2] 大小释放
C++14 引入了声明适合大小释放的全局重载的机会,这在 C++11 中是不可能的。operator delete
但是,该标准还规定,开发人员不能只声明以下两个相关功能之一,它必须声明一个,或者同时声明两个;这在 [new.delete.single]p11 中说明。
void operator delete (void*) noexcept;
void operator delete (void*, std::size_t) noexcept; // sized deallocation
有关潜在问题的更多信息:
重新定义全局未调整大小版本的现有程序也没有 定义大小版本。当实现引入 版本,替换将不完整,并且很可能是 程序将调用实现提供的大小的 DealLocator 使用程序员提供的分配器分配的对象。
注意:引自 n3536 - C++ 大小的释放
(注意:更多感兴趣的内容可以在Lawrence Crowl撰写的标题为n3536 - C++大小的Deallocation的论文中找到 )
C.3.3] member-functions,不再隐式constexpr
const
在 C++14 中,constexpr 有许多变化,但唯一会改变 C++11 和 C++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++11 和 C++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++14 中编译为 C++11 编写的代码,其中使用了这样的函数,很可能只是无法编译。
(注意:有一些编写代码的方法不会编译失败,并且具有不同的行为,这取决于从标准库中删除std::gets
)
评论
std::is_same<decltype(i), std::initializer_list<int>>::value
auto i {1}
true
std::d ecay
添加到 std::common_type
的实现中。所以代码 like 变得无效。std::common_type<int&, int&>::type f(int& x){return x;} /*...*/ int x{}; f(x) = 2;
common_type
std::gets
评论