Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What changes introduced in C++14 can potentially break a program written in C++11?

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.

  • According to the Standard: What changes introduced in C++14 can potentially break a program written in C++11?
like image 964
Filip Roséen - refp Avatar asked Jun 01 '14 14:06

Filip Roséen - refp


People also ask

What is the difference between C ++ 11 and C ++ 14?

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; .

What changed in C ++ 11?

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.


1 Answers

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.


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.

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.


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.

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.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.

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 )


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.

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:

  • Andrzej's C++ blog - “constexpr” function is not “const”
  • open-std.org - constexpr member functions and implicit const
  • (open-std.org - Relaxing constraints on constexpr functions)


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 

C.3.4] Removal of 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 )

like image 119
Filip Roséen - refp Avatar answered Oct 02 '22 06:10

Filip Roséen - refp