Ich weiß, dass mindestens eine der Änderungen in C++11 dazu führt, dass alter Code nicht mehr kompiliert werden kann: die Einführung von explicit operator bool()
in der Standardbibliothek und ersetzt alte Instanzen von operator void*()
. Zugegeben, der Code, den dies brechen wird, ist wahrscheinlich Code, der von vornherein nicht hätte gültig sein sollen, aber es ist trotzdem eine Breaking Change: Programme, die früher gültig waren, sind es nicht mehr.
Gibt es weitere wichtige Änderungen?
Das FDIS hat im Anhang einen Abschnitt für Inkompatibilitäten C.2
“C++ und ISO C++ 2003”.
Zusammenfassung, die FDIS hier umformuliert, um sie (besser) als SO-Antwort geeignet zu machen. Ich habe einige eigene Beispiele hinzugefügt, um die Unterschiede zu veranschaulichen.
Es gibt ein paar bibliotheksbezogene Inkompatibilitäten, deren Auswirkungen ich nicht genau kenne, daher überlasse ich es anderen, darauf näher einzugehen.
Kernsprache
#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 .
Neue Schlüsselwörter: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert und thread_local
Bestimmte Integer-Literale, die größer sind als durch long dargestellt werden können, könnten sich von einem Integer-Typ ohne Vorzeichen zu Long Long mit Vorzeichen ändern.
Gültiger C++ 2003-Code, der eine ganzzahlige Division verwendet, rundet das Ergebnis gegen 0 oder gegen minus unendlich, während C++0x das Ergebnis immer gegen 0 rundet.
(zugegebenermaßen kein wirkliches Kompatibilitätsproblem für die meisten Leute).
Gültiger C++ 2003-Code, der das Schlüsselwort verwendet auto
als Speicherklassenbezeichner kann in C++0x ungültig sein.
Einengende Konvertierungen verursachen Inkompatibilitäten mit C++03. Beispielsweise ist der folgende Code in C++ 2003 gültig, aber in diesem Internationalen Standard ungültig, da double to int eine einschränkende Konvertierung ist:
int x[] = { 2.0 };
Implizit deklarierte spezielle Elementfunktionen werden als gelöscht definiert, wenn die implizite Definition falsch formatiert gewesen wäre.
Ein gültiges C++ 2003-Programm, das eine dieser speziellen Elementfunktionen in einem Kontext verwendet, in dem die Definition nicht erforderlich ist (z. B. in einem Ausdruck, der möglicherweise nicht ausgewertet wird), wird falsch formatiert.
Beispiel von mir:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
Solche Größentricks wurden von einigen SFINAE verwendet und müssen jetzt geändert werden 🙂
Vom Benutzer deklarierte Destruktoren haben eine implizite Ausnahmespezifikation.
Beispiel von mir:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
Dieser Code ruft terminate
in C++0x, aber nicht in C++03. Da die implizite Ausnahmespezifikation von A::~A
in C++0x ist noexcept(true)
.
Eine gültige C++ 2003-Deklaration mit export
ist in C++0x falsch formatiert.
Ein gültiger C++ 2003-Ausdruck, der enthält >
unmittelbar gefolgt von einem anderen >
kann jetzt so behandelt werden, als würden zwei Vorlagen geschlossen.
In C++03, >>
wäre immer das Shift-Operator-Token.
Abhängige Aufrufe von Funktionen mit interner Verknüpfung zulassen.
Beispiel von mir:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f
int main() { g(0); }
In C++03 ruft dies auf f(long)
aber in C++0x ruft dies auf f(int)
. Es sollte beachtet werden, dass sowohl in C++03 als auch in C++0x die folgenden Aufrufe f(B)
(Der Instanziierungskontext berücksichtigt immer noch nur externe Verknüpfungsdeklarationen).
struct B { };
struct A : B { };
template<typename T>
void g(T t) { f
static void f(A) { }
void f(B) { }
int main() { A a; g(a); }
Je besser passend f(A)
wird nicht übernommen, da keine externe Verlinkung vorhanden ist.
Änderungen in der Bibliothek
Gültiger C++ 2003-Code, der Bezeichner verwendet, die der C++-Standardbibliothek von C++0x hinzugefügt wurden, kann möglicherweise nicht kompiliert werden oder zu anderen Ergebnissen in dieser Internationalen Norm führen.
Gültiger C++ 2003-Code that #includes
Header mit Namen von Headern der neuen C++0x-Standardbibliothek können in dieser Internationalen Norm ungültig sein.
Gültiger C++ 2003-Code, der kompiliert wurde und erwartet, dass sich Swap befindet <algorithm>
müssen möglicherweise stattdessen enthalten <utility>
Der globale Namespace posix
ist jetzt der Standardisierung vorbehalten.
Gültiger C++ 2003-Code, der definiert override
, final
, carries_dependency
oder noreturn
als Makros ist in C++0x ungültig.
Die Bedeutung des Schlüsselworts auto hat sich geändert.
Veränderung brechen?
Nun, zum einen, wenn Sie verwendet haben decltype
, constexpr
, nullptr
etc. als Identifikatoren, dann könnten Sie in Schwierigkeiten geraten …
Einige grundlegende Inkompatibilitäten, die nicht im Abschnitt „Inkompatibilitäten“ behandelt werden:
C++0x behandelt den eingefügten Klassennamen als Vorlage, wenn der Name als Argument an einen Vorlagenvorlagenparameter übergeben wird, und als Typ, wenn er an einen Vorlagentypparameter übergeben wird.
Gültiger C++03-Code kann sich anders verhalten, wenn er darauf angewiesen ist, dass der eingefügte Klassenname in diesen Szenarien immer ein Typ ist. Beispielcode entnommen aus meinem 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 ruft der Code die zweite auf g
beide Male.
C++0x macht einige Namen, die in C++03 abhängig waren, jetzt nicht-abhängig. Und erfordert, dass die Namenssuche nach nicht abhängigen qualifizierten Namen, die sich auf Mitglieder der aktuellen Klassenvorlage beziehen, bei der Instanziierung wiederholt wird, und erfordert die Überprüfung, dass diese Namen auf die gleiche Weise wie im Kontext der Vorlagendefinition gesucht werden.
Gültiger C++03-Code, der von der Dominanzregel abhängt, wird aufgrund dieser Änderung möglicherweise nicht mehr kompiliert.
Beispiel:
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(); }
Dieser gültige C++03-Code, der aufruft A<int>::f
ist in C++0x nicht gültig, da die Namenssuche beim Instanziieren findet A<int>::f
im Gegensatz zu B::f
wodurch ein Konflikt mit der At-Definition-Suche verursacht wird.
Ob es sich hierbei um einen Defekt des FDIS handelt, ist derzeit noch nicht klar. Der Ausschuss ist sich dessen bewusst und wird die Situation bewerten.
Eine using-Deklaration, bei der der letzte Teil mit dem Bezeichner im letzten Teil des Qualifizierers im qualifizierten Namen identisch ist, der eine Basisklasse bezeichnet, diese using-Deklaration benennt nun den Konstruktor anstelle von Membern mit diesem Namen.
Beispiel:
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; }
Der obige Beispielcode ist wohlgeformt in C++03, aber schlecht geformt in C++0x, as A::B
ist immer noch unzugänglich in main
.
Stream-Extraktionsfehler werden anders behandelt.
Beispiel
#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
}
Änderungsvorschlag
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
Standardreferenz
[C++03: 22.2.2.1.2/11]:
Das Ergebnis der Verarbeitung der Stufe 2 kann eines von sein
- In Stufe 2 hat sich eine Folge von Zeichen angesammelt, die umgewandelt wird (nach den Regeln von
scanf
) auf einen Wert vom Typ von val
. Dieser Wert wird gespeichert in val
und ios_base::goodbit
darin gespeichert ist err
.
- Die in Stufe 2 akkumulierte Folge von Zeichen hätte verursacht
scanf
um einen Eingabefehler zu melden. ios_base::failbit
zugeordnet ist err
. [ed: Nothing is stored in val
.]
[C++11: 22.4.2.1.2/3]:
[..] Der zu speichernde numerische Wert kann einer der folgenden sein:
- Null, wenn die Konvertierungsfunktion nicht das gesamte Feld konvertiert.
ios_base::failbit
zugeordnet ist err
.
- der positivste darstellbare Wert, wenn das Feld einen zu großen positiven Wert darstellt, um dargestellt zu werden
val
. ios_base::failbit
zugeordnet ist err
.
- der negativste darstellbare Wert oder Null für einen vorzeichenlosen ganzzahligen Typ, wenn das Feld einen zu großen negativen Wert darstellt, um darin dargestellt zu werden
val
. ios_base::failbit
zugeordnet ist err
.
- der konvertierte Wert, andernfalls.
Der resultierende numerische Wert wird in gespeichert val
.
Implementierungen
-
AGB 4.8 korrekte Ausgaben für C++11:
Assertion `x == -1′ ist fehlgeschlagen
-
GCC 4.5-4.8 alle Ausgaben für C++03 Folgendes, was ein Fehler zu sein scheint:
Assertion `x == -1′ ist fehlgeschlagen
-
Visual C++ 2008 Express korrekte Ausgaben für C++03:
Behauptung fehlgeschlagen: x == 0
-
Visual C++ 2012 Express gibt für C++11 falsch aus, was ein Problem mit dem Implementierungsstatus zu sein scheint:
Behauptung fehlgeschlagen: x == 0
Inwiefern ist die Einführung expliziter Konvertierungsoperatoren eine bahnbrechende Änderung? Die alte Version bleibt genauso “gültig” wie zuvor.
Ja, die Änderung aus operator void*() const
zu explicit operator bool() const
wird eine bahnbrechende Änderung sein, aber nur, wenn sie auf eine Weise verwendet wird, die an und für sich falsch ist. Konformer Code wird nicht beschädigt.
Eine weitere bahnbrechende Änderung ist das Verbot von einschränkenden Konvertierungen während der Initialisierung von Aggregaten:
int a[] = { 1.0 }; // error
Bearbeiten: Nur zur Erinnerung, std::identity<T>
wird in C++0x entfernt (siehe Hinweis). Es ist eine praktische Struktur, um Typen abhängig zu machen. Da die Struktur wirklich nicht viel tut, sollte dies das Problem beheben:
template<class T>
struct identity{
typedef T type;
};
Es gibt zahlreiche Änderungen an der Containerbibliothek, die einen effizienteren Code ermöglichen, aber die Abwärtskompatibilität für einige Eckfälle stillschweigend unterbrechen.
Betrachten Sie zum Beispiel std::vector
Standardkonstruktion, C++0x und Breaking Changes.
9889200cookie-checkWelche Breaking Changes werden in C++11 eingeführt?yes
Entfernen der Bedeutung von
export
Stichwort? Ich hole mir einen Mantel.– Steve Jessop
19. Juni 2011 um 0:06 Uhr
Weißt du, ich würde es nicht als “brechende Änderung” bezeichnen … eher als “bestrafende Änderung”.
– Xeo
19. Juni 2011 um 0:07 Uhr
Wenn der ganze Papierkram, der für die Gründung einer solchen Gewerkschaft erforderlich ist, nur darauf wartet, abgesegnet zu werden, klar, warum nicht?
– Dennis Zickefoose
19. Juni 2011 um 0:07 Uhr
@Xeo:
mystream.good()
ist nicht dasselbe wiebool(mystream)
?good()
ist wahr, wenn kein Flag gesetzt ist.bool(mystream)
ist immer noch falsch, wenn nureofbit
eingestellt ist.!mystream.fail()
wäre das richtige Äquivalent.– R.Martinho Fernandes
19. Juni 2011 um 0:32 Uhr
Anmerkung des Moderators: “Bitte halten Sie Kommentare zum Thema mit der Frage oder Antwort bereit. Wenn eine Frage oder Antwort diskutiert wird, sollte sich die Diskussion genau um diese Frage oder Antwort drehen. Diskussionen sind im Allgemeinen für Stack Overflow nicht konstruktiv. Antagonisieren ist sicherlich nicht.“
– Tim Post
♦
19. Juni 2011 um 15:11 Uhr