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

时间:2021-03-17 21:04:56

Introduction

介绍

With the C++14 (aka. C++1y) Standard in a state close to being final, programmers must ask themselves about backwards compatibility, and issues related to such.

与c++ 14(又名。c++ 1y)标准在接近最终的状态下,程序员必须问自己关于向后兼容性的问题,以及相关的问题。


The question

这个问题

In the answers of this question it is stated that the Standard has an Appendix dedicated to information regarding changes between revisions.

在这个问题的答案中,它说明了标准有一个附录,专门用于关于修订之间的变更的信息。

It would be helpful if these potential issues in the previously mentioned Appendix could be explained, perhaps with the help of any formal documents related to what is mentioned there.

如果前面提到的附录中的这些潜在问题能够得到解释,也许可以借助与上面提到的内容有关的任何正式文件加以说明,那将是很有帮助的。

  • According to the Standard: What changes introduced in C++14 can potentially break a program written in C++11?
  • 根据标准:c++ 14中引入的哪些更改可能会破坏一个用c++ 11编写的程序?

1 个解决方案

#1


228  

Note: In this post I consider a "breaking change" to be either, or both, of;
1. a change that will make legal C++11 ill-formed when compiled as C++14, and;
2. a change that will change the runtime behavior when compiled as C++14, vs C++11.

注意:在这篇文章中,我认为一个“突破性的变化”,或者两者兼而有之;1。当编译为c++ 14时,使合法的c++ 11变得不完整的更改;2。当编译为c++ 14时,将改变运行时行为的更改,vs . c++ 11。


C++11 vs C++14, what does the Standard say?

The Standard draft (n3797) has a section dedicated for just this kind of information, where it describes the (potentially breaking) differences between one revision of the standard, and another.

标准草案(n3797)中有一节专门介绍这类信息,其中描述了标准的一个修订与另一个修订之间(可能会破坏)的差异。

This post has used that section, [diff.cpp11], as a base for a semi-elaborate discussion regarding the changes that could affect code written for C++11, but compiled as C++14.

这篇文章使用了这个部分[diff]。cpp11],作为对可能影响为c++ 11编写但编译为c++ 14的代码的更改进行半详细讨论的基础。


C.3.1] Digit Separators

The digit separator was introduced so that one could, in a more readable manner, write numeric literals and split them up in a way that is more natural way.

引入了数字分隔符,以便人们能够以一种更可读的方式编写数字文本并以更自然的方式将它们分割开来。

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

It's easy to see that (2) is much easier to read than (1) in the above snippet, while both initializers have the same value.

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

The potential issue regarding this feature is that the single-quote always denoted the start/end of a character-literal in C++11, but in C++14 a single-quote can either be surrounding a character-literal, or used in the previously shown manner (2).

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


Example Snippet, legal in both C++11 and C++14, but with different behavior.

示例代码片段,在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 }`

( Note: More information regarding single-quotes as digit separators can be found in n3781.pdf )

(注:关于单引号作为数字分隔符的更多信息可以在n3781中找到。pdf)


C.3.2] Sized Deallocation

C++14 introduces the opportunity to declare a global overload of operator delete suitable for sized deallocation, something which wasn't possible in C++11.

c++ 14引入了一个声明操作符delete的全局重载的机会,该重载适合于大小的deallocation,这在c++ 11中是不可能的。

However, the Standard also mandates that a developer cannot declare just one of the two related functions below, it must declare either none, or both; which is stated in [new.delete.single]p11.

但是,该标准还规定,开发人员不能只声明下面两个相关函数中的一个,它必须声明none或both;在[new.delete.single]p11中声明。

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


Further information regarding the potential problem:

关于潜在问题的进一步资料:

Existing programs that redefine the global unsized version do not also define the sized version. When an implementation introduces a sized version, the replacement would be incomplete and it is likely that programs would call the implementation-provided sized deallocator on objects allocated with the programmer-provided allocator.

重新定义全局非大小版本的现有程序也不定义大小版本。当一个实现引入一个大小的版本时,替换将是不完整的,并且程序可能会调用由程序提供的分配程序分配的对象的大小分配程序。

Note: Quote taken from n3536 - C++ Sized Deallocation

注:报价取自n3536 - c++大小的交易

( Note: More of interest is available in the paper titled n3536 - C++ Sized Deallocation, written by Lawrence Crowl )

(注:更多的兴趣可以在Lawrence Crowl撰写的题为n3536 - c++ size Deallocation的论文中找到)


C.3.3] constexpr member-functions, no longer implicitly const

There are many changes to constexpr in C++14, but the only change that will change semantics between C++11, and C++14 is the constantness of a member-function marked as constexpr.

在c++ 14中,constexpr有很多变化,但是在c++ 11和c++ 14之间,唯一的变化是constexpr标记为constexpr的成员函数的稳定性。

The rationale behind this change is to allow constexpr member-functions to mutate the object to which they belong, something which is allowed due to the relaxation of constexpr.

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

struct A { constexpr int func (); };

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


Recommended material on this change, and why it is important enough to introduce potential code-breakage:

关于此变更的推荐材料,以及为什么引入潜在的代码破坏足够重要:


Example snippet, legal in both C++11 and C++14, but with different behavior

示例代码片段,在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] Removal of std::gets

std::gets has been removed from the Standard Library because it is considered dangerous.

get已经从标准库中删除,因为它被认为是危险的。

The implications of this is of course that trying to compile code written for C++11, in C++14, where such a function is used will most likely just fail to compile.

这当然意味着,在c++ 14中尝试编译为c++ 11编写的代码,在c++ 14中使用这样的函数,很可能无法编译。


( Note: there are ways of writing code that doesn't fail to compile, and have different behavior, that depends on the removal of std::gets from the Standard Library )

(注意:有一些编写代码的方法不会失败,并且有不同的行为,这取决于删除标准库中的std::get)

#1


228  

Note: In this post I consider a "breaking change" to be either, or both, of;
1. a change that will make legal C++11 ill-formed when compiled as C++14, and;
2. a change that will change the runtime behavior when compiled as C++14, vs C++11.

注意:在这篇文章中,我认为一个“突破性的变化”,或者两者兼而有之;1。当编译为c++ 14时,使合法的c++ 11变得不完整的更改;2。当编译为c++ 14时,将改变运行时行为的更改,vs . c++ 11。


C++11 vs C++14, what does the Standard say?

The Standard draft (n3797) has a section dedicated for just this kind of information, where it describes the (potentially breaking) differences between one revision of the standard, and another.

标准草案(n3797)中有一节专门介绍这类信息,其中描述了标准的一个修订与另一个修订之间(可能会破坏)的差异。

This post has used that section, [diff.cpp11], as a base for a semi-elaborate discussion regarding the changes that could affect code written for C++11, but compiled as C++14.

这篇文章使用了这个部分[diff]。cpp11],作为对可能影响为c++ 11编写但编译为c++ 14的代码的更改进行半详细讨论的基础。


C.3.1] Digit Separators

The digit separator was introduced so that one could, in a more readable manner, write numeric literals and split them up in a way that is more natural way.

引入了数字分隔符,以便人们能够以一种更可读的方式编写数字文本并以更自然的方式将它们分割开来。

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

It's easy to see that (2) is much easier to read than (1) in the above snippet, while both initializers have the same value.

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

The potential issue regarding this feature is that the single-quote always denoted the start/end of a character-literal in C++11, but in C++14 a single-quote can either be surrounding a character-literal, or used in the previously shown manner (2).

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


Example Snippet, legal in both C++11 and C++14, but with different behavior.

示例代码片段,在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 }`

( Note: More information regarding single-quotes as digit separators can be found in n3781.pdf )

(注:关于单引号作为数字分隔符的更多信息可以在n3781中找到。pdf)


C.3.2] Sized Deallocation

C++14 introduces the opportunity to declare a global overload of operator delete suitable for sized deallocation, something which wasn't possible in C++11.

c++ 14引入了一个声明操作符delete的全局重载的机会,该重载适合于大小的deallocation,这在c++ 11中是不可能的。

However, the Standard also mandates that a developer cannot declare just one of the two related functions below, it must declare either none, or both; which is stated in [new.delete.single]p11.

但是,该标准还规定,开发人员不能只声明下面两个相关函数中的一个,它必须声明none或both;在[new.delete.single]p11中声明。

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


Further information regarding the potential problem:

关于潜在问题的进一步资料:

Existing programs that redefine the global unsized version do not also define the sized version. When an implementation introduces a sized version, the replacement would be incomplete and it is likely that programs would call the implementation-provided sized deallocator on objects allocated with the programmer-provided allocator.

重新定义全局非大小版本的现有程序也不定义大小版本。当一个实现引入一个大小的版本时,替换将是不完整的,并且程序可能会调用由程序提供的分配程序分配的对象的大小分配程序。

Note: Quote taken from n3536 - C++ Sized Deallocation

注:报价取自n3536 - c++大小的交易

( Note: More of interest is available in the paper titled n3536 - C++ Sized Deallocation, written by Lawrence Crowl )

(注:更多的兴趣可以在Lawrence Crowl撰写的题为n3536 - c++ size Deallocation的论文中找到)


C.3.3] constexpr member-functions, no longer implicitly const

There are many changes to constexpr in C++14, but the only change that will change semantics between C++11, and C++14 is the constantness of a member-function marked as constexpr.

在c++ 14中,constexpr有很多变化,但是在c++ 11和c++ 14之间,唯一的变化是constexpr标记为constexpr的成员函数的稳定性。

The rationale behind this change is to allow constexpr member-functions to mutate the object to which they belong, something which is allowed due to the relaxation of constexpr.

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

struct A { constexpr int func (); };

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


Recommended material on this change, and why it is important enough to introduce potential code-breakage:

关于此变更的推荐材料,以及为什么引入潜在的代码破坏足够重要:


Example snippet, legal in both C++11 and C++14, but with different behavior

示例代码片段,在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] Removal of std::gets

std::gets has been removed from the Standard Library because it is considered dangerous.

get已经从标准库中删除,因为它被认为是危险的。

The implications of this is of course that trying to compile code written for C++11, in C++14, where such a function is used will most likely just fail to compile.

这当然意味着,在c++ 14中尝试编译为c++ 11编写的代码,在c++ 14中使用这样的函数,很可能无法编译。


( Note: there are ways of writing code that doesn't fail to compile, and have different behavior, that depends on the removal of std::gets from the Standard Library )

(注意:有一些编写代码的方法不会失败,并且有不同的行为,这取决于删除标准库中的std::get)