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.
C++11 allowed lambda functions to deduce the return type based on the type of the expression given to the return statement. C++14 provides this ability to all functions. It also extends these facilities to lambda functions, allowing return type deduction for functions that are not of the form return expression; .
The C++11 Standard Library was also revamped with new algorithms, new container classes, atomic operations, type traits, regular expressions, new smart pointers, async() facility, and of course a multithreading library. A complete list of the new core and library features of C++11 is available here.
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; } };
Obj const a = {}; int const x = a.func (123); // int const x = 1; <-- C++11 // int const x = 2; <-- C++14
std::gets
std::gets
has been removed from the Standard Library because it is considered dangerous.
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.
( 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 )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With