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.
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.
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.
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.
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.
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.
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).
Example Snippet, legal in both C++11 and C++14, but with different behavior.
#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 )
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.
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.
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
( Note: More of interest is available in the paper titled n3536 - C++ Sized Deallocation, written by Lawrence Crowl )
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.
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.
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
struct Obj {
constexpr int func (int) {
return 1;
}
constexpr int func (float) const {
return 2;
}
};