231

I know that at least one of the changes in C++11 that will cause some old code to stop compiling: the introduction of explicit operator bool() in the standard library, replacing old instances of operator void*(). Granted, the code that this will break is probably code that should not have been valid in the first place, but it's still a breaking change nonetheless: programs that used to be valid no longer are.

Are there any other breaking changes?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • @Downvoter: I like how the question mentions "C++11" at all, since "C++11" does not exist yet. – Lightness Races in Orbit Jun 19 '11 at 00:00
  • @Tomalak: whatever. It will exist. Even if it doesn't start existing this year, it will be C++11. Compare with Fortran 2008, which only started existing in 2010. – R. Martinho Fernandes Jun 19 '11 at 00:01
  • 1
    Removing the meaning of the `export` keyword? I'll get me coat. – Steve Jessop Jun 19 '11 at 00:06
  • 7
    You know, I wouldn't call it the changing of conversion-to-bool a "breaking change" ... more like a "punishing change". – Xeo Jun 19 '11 at 00:07
  • 4
    When all the paperwork neccessary to create such a union is just waiting to be rubber stamped, sure, why not? – Dennis Zickefoose Jun 19 '11 at 00:07
  • 1
    @Xeo: that's one kind of breaking change, yes. Breaking the code of people we hate. – Steve Jessop Jun 19 '11 at 00:10
  • And doesn't it break somewhat reasonable code like `void foo(int x, bool y); foo(23, mystream);`? Nowhere does the C++ standard say, "look, we really only want you to use streams specifically as the condition in a `while` loop, not in any other context where you need a boolean". – Steve Jessop Jun 19 '11 at 00:18
  • 1
    @Steve: That code should use `mystream.good()`... The conversion-to-bool I think was only for shorthanding the check in *boolean contexts* as it's called in the draft. – Xeo Jun 19 '11 at 00:29
  • 3
    @Xeo: `mystream.good()` is not the same as `bool(mystream)`? `good()` is true if no flag is set. `bool(mystream)` is still false if only `eofbit` is set. `!mystream.fail()` would be the correct equivalent. – R. Martinho Fernandes Jun 19 '11 at 00:32
  • @Martinho: Yes, I just researched that in the C++03 standard, you are right. – Xeo Jun 19 '11 at 00:39
  • @Xeo: to be equivalent doesn't it have to be `!mystream.fail()` rather than `mystream.good()`? Which is kind of why people *should* be using the conversion rather than trying to remember what the dog's breakfast of status-checking functions on `basic_ios` actually mean. If the code "should" use anything different, then it's `(bool)mystream`, which of course does still work in C++0x, but there's nothing in C++03 to suggest it should be required. Hence, breaking change. – Steve Jessop Jun 19 '11 at 00:43
  • This is, in essence a question asking for a list of something. It's also very specific and will probably be well maintained. In the spirit of that, I'm making this CW. – Tim Post Jun 19 '11 at 15:01
  • 2
    **Moderator note**: "_Please keep comments on topic with the question or answer at hand. When discussing a question or answer, the discussion should be about just that, the question or answer at hand. Debating, in general is not constructive for Stack Overflow. Antagonizing surely is not._" – Tim Post Jun 19 '11 at 15:11
  • Related: http://stackoverflow.com/questions/6473218/challenge-programmatically-detect-whether-code-is-compiled-with-c03-or-c0x – Armen Tsirunyan Jun 25 '11 at 11:30

9 Answers9

181

The FDIS has a section for incompatibilities, at appendix C.2 "C++ and ISO C++ 2003".

Summary, paraphrasing the FDIS here, to make it (better) suitable as a SO answer. I added some examples of my own to illustrate the differences.

There are a few library-related incompatibilities where I don't exactly know the implications of, so I leave those for others to elaborate on.

Core language


#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"

#define _x "there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .

New keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local


Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.


Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas C++0x always rounds the result toward 0.

(admittedly not really a compatibility problem for most people).


Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in C++0x.


Narrowing conversions cause incompatibilities with C++03. For example, the following code is valid in C++ 2003 but invalid in this International Standard because double to int is a narrowing conversion:

int x[] = { 2.0 };

Implicitly-declared special member functions are defined as deleted when the implicit definition would have been ill-formed.

A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expresion that is not potentially evaluated) becomes ill-formed.

Example by me:

struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }

Such sizeof tricks have been used by some SFINAE, and needs to be changed now :)


User-declared destructors have an implicit exception specification.

Example by me:

struct A {
  ~A() { throw "foo"; }
};

int main() { try { A a; } catch(...) { } }

This code calls terminate in C++0x, but does not in C++03. Because the implicit exception specification of A::~A in C++0x is noexcept(true).


A valid C++ 2003 declaration containing export is ill-formed in C++0x.


A valid C++ 2003 expression containing > followed immediately by another > may now be treated as closing two templates.

In C++03, >> would always be the shift-operator token.


Allow dependent calls of functions with internal linkage.

Example by me:

static void f(int) { }
void f(long) { }

template<typename T>
void g(T t) { f(t); }

int main() { g(0); }

In C++03, this calls f(long), but in C++0x, this calls f(int). It should be noted that in both C++03 and C++0x, the following calls f(B) (the instantiation context still only considers extern linkage declarations).

struct B { };
struct A : B { };

template<typename T>
void g(T t) { f(t); }

static void f(A) { }
void f(B) { }

int main() { A a; g(a); }

The better matching f(A) is not taken, because it does not have external linkage.


Library changes

Valid C++ 2003 code that uses any identifiers added to the C++ standard library of C++0x may fail to compile or produce different results in This International Standard.


Valid C++ 2003 code that #includes headers with names of new C++0x standard library headers may be invalid in this International Standard.


Valid C++ 2003 code that has been compiled expecting swap to be in <algorithm> may have to instead include <utility>


The global namespace posix is now reserved for standardization.


Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in C++0x.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • "Allow dependent calls of functions with internal linkage." Could you please elaborate on the difference between your two examples? I'm clearly missing something. – Dennis Zickefoose Jun 19 '11 at 14:56
  • @Dennis the change was introduced by http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 . Although they don't comment on the fact, the "instantiation context" still consists of only "the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit". So the change they made only affects the lookup in the definition context. – Johannes Schaub - litb Jun 19 '11 at 15:33
  • In my first example given, the internal-linkage function was visible and found in the definition context of the template. In my second example, the internal linkage function would need to be part of the instantiation context to be found. But since it isn't, it cannot be found. – Johannes Schaub - litb Jun 19 '11 at 15:34
  • Incidentally, I think the only case where it's safe for a template definition context to find a function with internal linkage is when the function template specialization is only explicitly instantiated instantiated in one TU (where the template is defined), and all other TUs rely on that explicit instantiation. In all other cases (where the other TUs would instantiate the specialization themselfs), you would violate the ODR by having the template definition use a different (internal linkage) function each time. – Johannes Schaub - litb Jun 19 '11 at 15:39
  • So I'm not sure why they kept the restriction on the instantiation context - there would only be one (explicit) instantiation, and that instantiation would use internal linkage functions found in the instantiation context of the instantiating TU. Just like it would for the definition context. Incidentally, I think if we would still have `export`, then *I think* the other TUs wouldn't need to rely on the explicit instantiation, but could instantiate the template themselfs. *Then* it would make a difference whether or not internal linkage functions are visible in the instantiation context. – Johannes Schaub - litb Jun 19 '11 at 15:43
  • Because then the template definition would *not* violate the ODR (the definition would still only be visible in the single TU and use only incarnation of the internal linkage function), but because of `export`, the other TUs could produce instantiations that could use internal linkage functions of *their* TU, and in each such TU, since the functions have internal linkage, the instantiations would use different functions, and thus violate the ODR. But since `export` is gone, such considerations are out of scope now. – Johannes Schaub - litb Jun 19 '11 at 15:45
  • I considered asking for that clarification in a separate question. Given the breadth of your response, perhaps that would have been the better choice after all :-) It makes sense now, thanks. – Dennis Zickefoose Jun 19 '11 at 18:41
  • @ᐅJohannesSchaub-litbᐊ: you are wrong about allow dependent calls of functions with internal linkage. The example given by you outputs f(int) both in C++03 & C++11. See this question: http://stackoverflow.com/questions/33675088/dependent-calls-of-functions-with-internal-linkage-in-c03-c11 – Destructor Nov 13 '15 at 18:56
  • @pravasi i haven't made any statement about how compilers treat those differences.. Most compilers have tradeoffs up to which detail they implement older standards. And for some level of detail simply implement the c++11 behavior even in c++03 mode – Johannes Schaub - litb Nov 13 '15 at 19:16
  • The #define examples should still work, as it gets ran before the parsing – JVApen Apr 24 '19 at 11:36
  • @JVApen that depends on whether the preprocessor actually replaces it, or not (probably the same applies to the user-defined literals example). A note in the Standard indicates that it doesn't replace it: "Since, by macro-replacement time, all character literals and string literals are preprocessing tokens, not sequences possibly containing identifier-like subsequences (see [lex.phases], translation phases), they are never scanned for macro names or parameters." – Johannes Schaub - litb Apr 24 '19 at 12:58
  • @JohannesSchaub-litb in eg Allow dependent calls of functions with internal linkage. in both examples one option is static and second option is non static but in 2nd eg u chose non static because there was no external linkage, I have doubt in 1st eg also there was no external linkage in non static option. Can you please elaborate? – a learner Dec 27 '20 at 16:43
30

The meaning of the auto keyword changed.

arsenm
  • 2,903
  • 1
  • 23
  • 23
  • 9
    If you've been using the `auto` keyword, something is very wrong with your code. Why on earth would you use it? – Elazar Leibovich Jun 19 '11 at 09:03
  • That's not a _breaking change_. Every valid C++03 use of `auto` remains valid in C++11. – Drew Dormann Jul 01 '14 at 16:48
  • 13
    @DrewDormann `int main() { auto int i = 0; return i; }` is perfectly valid C++03, but a syntax error in C++11. The only warning I can get compilers to give for it in C++03 mode is a warning about compatibility. –  Sep 14 '14 at 10:37
25

Breaking change?

Well, for one thing, if you used decltype, constexpr, nullptr, etc. as identifiers then you may be in trouble...

Downvoter
  • 551
  • 4
  • 14
21

Some core incompatibilities that are not covered by the incompatibilities section:


C++0x treats the injected class name as a template, if the name is passed as an argument to a template template parameter, and as a type if it is passed to a template type parameter.

Valid C++03 code may behave differently if it relies on the injected class name to be always a type in these scenarios. Example code taken from my clang PR

template<template<typename> class X>
struct M { };

template<template<typename> class X>
void g(int = 0); // #1

template<typename T>
void g(long = 0); // #2

template<typename T>
struct A {
  void f() {
    g<A>(); /* is ambiguous in C++0x */
    g<A>(1); /* should choose #1 in C++0x */
  }
};

void h() {
  A<int> a;
  a.f();
}

In C++03, the code calls the second g both times.


C++0x makes some names that were dependent in C++03 to be now non-dependent. And requires name lookup for non-dependent qualified names that refer to members of the current class template to be repeated at instantiation, and requires verification that these names lookup the same way as done at the template definition context.

Valid C++03 code that depends on the dominance rule may now not compile anymore because of this change.

Example:

struct B { void f(); };

template<typename T>
struct A : virtual B { void f(); };

template<typename T>
struct C : virtual B, A<T> {
  void g() { this->f(); }
};

int main() { C<int> c; c.g(); }

This valid C++03 code that calls A<int>::f is not valid in C++0x, because name lookup when instantiating will find A<int>::f as opposed to B::f, causing a conflict with the at-definition lookup.

At this point, it is not clear whether that is a defect in the FDIS. The committee is aware of this and will evaluate the situation.


A using declaration where the last part is the same as the identifier in the last part of the qualifier in the qualified name denoting a base class, that using declaration now names the constructor, instead of members with that name.

Example:

struct A { protected: int B; };
typedef A B;

struct C : B {
  // inheriting constructor, instead of bringing A::B into scope
  using B::B;
};

int main() { C c; c.B = 0; }

The above example code is well-formed in C++03, but ill-formed in C++0x, as A::B is still inaccessible in main.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
14

Stream extraction failure is treated differently.

Example

#include <sstream>
#include <cassert>

int main()
{
   std::stringstream ss;
   ss << '!';
   
   int x = -1;
   
   assert(!(ss >> x)); // C++03 and C++11
   assert(x == -1);    // C++03
   assert(x == 0);     // C++11
}

Change proposal

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23

Standard reference

[C++03: 22.2.2.1.2/11]: The result of stage 2 processing can be one of

  • A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val. This value is stored in val and ios_base::goodbit is stored in err.
  • The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err. [ed: Nothing is stored in val.]

[C++11: 22.4.2.1.2/3]: [..] The numeric value to be stored can be one of:

  • zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
  • the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
  • the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
  • the converted value, otherwise.

The resultant numeric value is stored in val.

Implementations

  • GCC 4.8 correctly outputs for C++11:

    Assertion `x == -1' failed

  • GCC 4.5-4.8 all output for C++03 the following, which would appear to be a bug:

    Assertion `x == -1' failed

  • Visual C++ 2008 Express correctly outputs for C++03:

    Assertion failed: x == 0

  • Visual C++ 2012 Express incorrectly outputs for C++11, which would appear to be a status-of-implementation issue:

    Assertion failed: x == 0

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
13

How is the introduction of explicit conversion operators a breaking change? The old version will still just be as "valid" as before.

Yes, the change from operator void*() const to explicit operator bool() const will be a breaking change, but only if it is used in a way that is wrong in and out of itself. Conforming code won't be broken.

Now, another breaking change is the banning of narrowing conversions during aggregate initialization:

int a[] = { 1.0 }; // error

Edit: Just rememberer, std::identity<T> will be removed in C++0x (see the note). It's a convenience struct to make types dependent. Since the struct really doesn't do much, this should fix it:

template<class T>
struct identity{
  typedef T type;
};
Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • If standard library objects had explicit conversions added, then existing implicit conversions may stop working. But I can't imagine a scenario where the conversion wouldn't be valid and do something useful. – Dennis Zickefoose Jun 18 '11 at 23:57
  • The introduction is a breaking change because it's going to be *replacing* the existing `operator void*`. – R. Martinho Fernandes Jun 18 '11 at 23:59
  • @Dennis: Aaah, I see now what @Martinho meant. But it will only be a breaking change if people used it other than intended. – Xeo Jun 18 '11 at 23:59
  • "but only if it is used in a way that is wrong in and out of itself" -- `bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }` There's nothing really wrong with that in C++03, yet it has become an error in C++11. (Note: GCC 4.9 still has `operator void*() const` here, which is why it does accept the code in C++11 mode.) –  Sep 14 '14 at 10:54
  • `std::identity` wasn't removed in C++11, because it wasn't part of C++03. It did briefly exist in the draft for C++11, and was removed from the draft prior to standardization. – Howard Hinnant Mar 18 '16 at 16:09
8

There are numerous changes to the containers library that allow more efficient code but silently break backwards compatibility for a few corner cases.

Consider, for example, std::vector, default construction, C++0x, and breaking changes.

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
7

There's been a lot of discussion of implicit move breaking backward compatibility

(an older page with relevant discussion)

If you read down into the comments, implicit move return is also a breaking change.

cmorse
  • 337
  • 1
  • 7
  • 15
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • The result of those discussions is that it got removed in almost all cases. Are there any issues with what got left? – Dennis Zickefoose Jun 19 '11 at 00:33
  • @Dennis: Yes. Your question was already asked, answered, and debated to death on [this followup page](http://cpp-next.com/archive/2011/02/w00t-w00t-nix-nix/) – Ben Voigt Jun 19 '11 at 00:34
  • Ahh, the mobile page did not show the comments. Either way, that's the much more useful link... Historical oddities of the standardization process aren't that relevant (unless you're using MSVC, which I believe uses that first draft). – Dennis Zickefoose Jun 19 '11 at 00:41
  • @Dennis: I think you're right. Moved the links around some in my answer. – Ben Voigt Jun 19 '11 at 00:43
  • Sadly, cpp-next.com doesn't exist anymore. For future reference these are pages saved by web.archive.org: [implicit move breaking backward compatibility](http://web.archive.org/web/20130127123111/http://cpp-next.com/archive/2011/02/w00t-w00t-nix-nix/) and [an older page with relevant discussion](http://web.archive.org/web/20140110035813/http://cpp-next.com/archive/2010/10/implicit-move-must-go/). – Max Truxa Jun 07 '15 at 08:41
6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C++03: valid.

C++0x: error: parameter declared 'auto'

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055