Welche bahnbrechenden Änderungen werden in C ++ 11 eingeführt?

227

Ich weiß, dass mindestens eine der Änderungen in C ++ 11 dazu führt, dass ein alter Code nicht mehr kompiliert wird: die Einführung explicit operator bool()in die Standardbibliothek, die alte Instanzen von ersetzt operator void*(). Zugegeben, der Code, den dies beschädigen wird, ist wahrscheinlich Code, der eigentlich nicht gültig sein sollte, aber es ist trotzdem eine wichtige Änderung: Programme, die früher gültig waren, sind es nicht mehr.

Gibt es noch andere wichtige Änderungen?

R. Martinho Fernandes
quelle
1
Die Bedeutung des exportSchlüsselworts entfernen ? Ich hole mir Mantel.
Steve Jessop
7
Weißt du, ich würde es nicht als "bahnbrechende Veränderung" bezeichnen, sondern als "bestrafende Veränderung".
Xeo
4
Wenn alle Papiere, die zur Schaffung einer solchen Gewerkschaft erforderlich sind, nur darauf warten, mit einem Stempel versehen zu werden, warum nicht?
Dennis Zickefoose
3
@Xeo: mystream.good()ist nicht dasselbe wie bool(mystream)? good()ist wahr, wenn kein Flag gesetzt ist. bool(mystream)ist immer noch falsch, wenn nur eofbitgesetzt ist. !mystream.fail()wäre das richtige Äquivalent.
R. Martinho Fernandes
2
Anmerkung des Moderators : " Bitte behalten Sie Kommentare zum Thema mit der Frage oder Antwort zur Hand. Wenn Sie eine Frage oder Antwort diskutieren, sollte sich die Diskussion nur um die Frage oder Antwort handeln. Die Debatte ist im Allgemeinen für den Stapelüberlauf nicht konstruktiv. Antagonisieren ist sicherlich nicht. "
Tim Post

Antworten:

178

Das FDIS enthält einen Abschnitt für Inkompatibilitäten im Anhang C.2"C ++ und ISO C ++ 2003".

Zusammenfassung, um das FDIS hier zu paraphrasieren, damit es (besser) als SO-Antwort geeignet ist. Ich habe einige eigene Beispiele hinzugefügt, um die Unterschiede zu veranschaulichen.

Es gibt einige bibliotheksbezogene Inkompatibilitäten, bei denen ich die Auswirkungen nicht genau kenne. Daher überlasse ich diese anderen, um sie zu erläutern.

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 ganzzahlige Literale, die größer sind als durch long dargestellt werden können, können sich von einem vorzeichenlosen Integer-Typ zu einem vorzeichenbehafteten long long ändern.


Gültiger C ++ 2003-Code, der eine ganzzahlige Division verwendet, rundet das Ergebnis gegen 0 oder gegen negative Unendlichkeit, während C ++ 0x das Ergebnis immer gegen 0 rundet.

(Zugegebenermaßen kein wirkliches Kompatibilitätsproblem für die meisten Menschen).


Gültiger C ++ 2003-Code, der das Schlüsselwort autoals Speicherklassenspezifizierer verwendet, ist in C ++ 0x möglicherweise ungültig.


Eingeschränkte Konvertierungen führen zu Inkompatibilitäten mit C ++ 03. Der folgende Code ist beispielsweise in C ++ 2003 gültig, in diesem internationalen Standard jedoch ungültig, da double to int eine engere Konvertierung darstellt:

int x[] = { 2.0 };

Implizit deklarierte spezielle Elementfunktionen werden als gelöscht definiert, wenn die implizite Definition fehlerhaft 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 fehlerhaft.

Beispiel von mir:

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

Solche Größen von Tricks 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 terminatein C ++ 0x auf, jedoch nicht in C ++ 03. Weil die implizite Ausnahmespezifikation von A::~Ain C ++ 0x ist noexcept(true).


Eine gültige C ++ 2003-Deklaration, die enthält, exportist in C ++ 0x fehlerhaft.


Ein gültiger C ++ 2003-Ausdruck, >der unmittelbar gefolgt von einem anderen Ausdruck enthält, >kann jetzt als Schließen von zwei Vorlagen behandelt werden.

In C ++ 03 >>wäre immer das Shift-Operator-Token.


Ermöglichen Sie abhängige Aufrufe von Funktionen mit interner Verknüpfung.

Beispiel von mir:

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

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

int main() { g(0); }

In C ++ 03 wird dies aufgerufen f(long), in C ++ 0x jedoch f(int). Es ist zu beachten, dass sowohl in C ++ 03 als auch in C ++ 0x die folgenden Aufrufe ausgeführt werden 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(t); }

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

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

Die bessere Übereinstimmung f(A)wird nicht genommen, da es keine externe Verknüpfung gibt.


Bibliotheksänderungen

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 unterschiedlichen Ergebnissen in diesem internationalen Standard führen.


Gültiger C ++ 2003-Code, der #includesHeader mit Namen neuer C ++ 0x-Standardbibliotheksheader enthält, ist in diesem internationalen Standard möglicherweise ungültig.


Gültiger C ++ 2003-Code, der kompiliert wurde und erwartet, dass Swap vorhanden ist, muss <algorithm>möglicherweise stattdessen enthalten sein<utility>


Der globale Namespace posixist jetzt für die Standardisierung reserviert.


Gültig C ++ 2003 - Code, der definiert , override, final, carries_dependency, oder noreturnals Makros in C ++ 0x ungültig ist.

Johannes Schaub - litb
quelle
"Ermöglichen Sie abhängige Aufrufe von Funktionen mit interner Verknüpfung." Könnten Sie bitte den Unterschied zwischen Ihren beiden Beispielen erläutern? Mir fehlt eindeutig etwas.
Dennis Zickefoose
@Dennis die Änderung wurde von open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 eingeführt . Obwohl sie die Tatsache nicht kommentieren, besteht der "Instanziierungskontext" immer noch nur aus "dem Satz von Deklarationen mit externer Verknüpfung, die vor dem Instanziierungspunkt der Vorlagenspezialisierung in derselben Übersetzungseinheit deklariert wurden". Die vorgenommene Änderung wirkt sich also nur auf die Suche im Definitionskontext aus.
Johannes Schaub - litb
In meinem ersten Beispiel war die interne Verknüpfungsfunktion sichtbar und wurde im Definitionskontext der Vorlage gefunden. In meinem zweiten Beispiel müsste die interne Verknüpfungsfunktion Teil des zu findenden Instanziierungskontexts sein. Aber da es nicht ist, kann es nicht gefunden werden.
Johannes Schaub - Litb
Übrigens denke ich, dass der einzige Fall, in dem es für einen Vorlagendefinitionskontext sicher ist, eine Funktion mit interner Verknüpfung zu finden, darin besteht, dass die Spezialisierung der Funktionsvorlage nur explizit in einer TU instanziiert wird (in der die Vorlage definiert ist) und alle anderen TUs sich darauf verlassen diese explizite Instanziierung. In allen anderen Fällen (in denen die anderen TUs die Spezialisierung selbst instanziieren würden) würden Sie die ODR verletzen, indem die Vorlagendefinition jedes Mal eine andere Funktion (interne Verknüpfung) verwendet.
Johannes Schaub - litb
Ich bin mir also nicht sicher, warum sie die Einschränkung des Instanziierungskontexts beibehalten haben - es würde nur eine (explizite) Instanziierung geben, und diese Instanziierung würde interne Verknüpfungsfunktionen verwenden, die im Instanziierungskontext der instanziierenden TU zu finden sind. Genau wie beim Definitionskontext. Übrigens, ich glaube , wenn wir noch haben würde export, dann denke ich , die anderen TUs würde nicht auf die explizite Instanziierung verlassen müssen, konnte aber die Vorlage themselfs instanziiert. Dann würde es einen Unterschied machen, ob interne Verknüpfungsfunktionen im Instanziierungskontext sichtbar sind oder nicht.
Johannes Schaub - litb
28

Die Bedeutung des Auto-Schlüsselworts wurde geändert.

Arsenal
quelle
9
Wenn Sie das autoSchlüsselwort verwendet haben, stimmt etwas mit Ihrem Code nicht. Warum um alles in der Welt würdest du es benutzen?
Elazar Leibovich
Das ist keine bahnbrechende Veränderung . Jede gültige Verwendung von C ++ 03 autobleibt in C ++ 11 gültig.
Drew Dormann
11
@DrewDormann int main() { auto int i = 0; return i; }ist perfekt gültig C ++ 03, aber ein Syntaxfehler in C ++ 11. Die einzige Warnung, die Compiler im C ++ 03-Modus dazu geben können, ist eine Warnung zur Kompatibilität.
24

Veränderung brechen?

Nun, für eine Sache, wenn man verwendet decltype, constexpr, nullptretc. als Bezeichner dann können Sie in Schwierigkeiten ...

Downvoter
quelle
21

Einige Kerninkompatibilitäten, die nicht im Abschnitt Inkompatibilitäten behandelt werden:


C ++ 0x behandelt den Namen der injizierten Klasse 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 der Name der injizierten Klasse in diesen Szenarien immer ein Typ ist. Beispielcode aus meiner 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 gbeide Male die Sekunde auf.


C ++ 0x macht einige Namen, die in C ++ 03 abhängig waren, jetzt unabhängig. Außerdem muss die Namenssuche für nicht abhängige qualifizierte Namen, die sich auf Mitglieder der aktuellen Klassenvorlage beziehen, bei der Instanziierung wiederholt werden, und es muss überprüft werden, ob diese Namen auf dieselbe 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 aufgerufen A<int>::fwird , ist in C ++ 0x nicht gültig, da die Namenssuche beim Instanziieren A<int>::fim Gegensatz zu gefunden B::fwird und einen Konflikt mit der Definitionssuche verursacht.

Zu diesem Zeitpunkt ist nicht klar, ob dies ein Defekt im FDIS ist. 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 für eine Basisklasse identisch ist. Diese using-Deklaration benennt jetzt den Konstruktor anstelle von Mitgliedern 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 in C ++ 03 gut geformt, in C ++ 0x jedoch schlecht geformt, da in C ++ 03 A::Bimmer noch nicht darauf zugegriffen werden kann main.

Johannes Schaub - litb
quelle
14

Stream-Extraktionsfehler werden unterschiedlich 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
}

Vorschlag ändern

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 der folgenden sein

  • In Stufe 2 wurde eine Folge von Zeichen akkumuliert, die (gemäß den Regeln von scanf) in einen Wert vom Typ konvertiert wird val. Dieser Wert wird in gespeichert valund ios_base::goodbitgespeichert in err.
  • Die in Stufe 2 akkumulierte Zeichenfolge hätte dazu geführt, dass scanfein Eingabefehler gemeldet wurde. ios_base::failbitist zugeordnet err. [ed: Nichts ist gespeichert 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::failbitist zugeordnet err.
  • der positivste darstellbare Wert, wenn das Feld einen Wert darstellt, der zu groß ist, um in dargestellt zu werden val. ios_base::failbitist zugeordnet err.
  • der negativste darstellbare Wert oder Null für einen vorzeichenlosen Ganzzahltyp, wenn das Feld einen Wert darstellt, der zu groß ist, um negativ dargestellt zu werden val. ios_base::failbitist zugeordnet err.
  • sonst der konvertierte Wert.

Der resultierende numerische Wert wird in gespeichert val.

Implementierungen

  • GCC 4.8 gibt korrekt für C ++ 11 aus :

    Behauptung `x == -1 'fehlgeschlagen

  • GCC 4.5-4.8 alle Ausgaben für C ++ 03 wie folgt, was ein Fehler zu sein scheint:

    Behauptung `x == -1 'fehlgeschlagen

  • Visual C ++ 2008 Express gibt korrekt für C ++ 03 aus:

    Behauptung fehlgeschlagen: x == 0

  • Visual C ++ 2012 Express gibt fälschlicherweise für C ++ 11 aus, was anscheinend ein Problem mit dem Implementierungsstatus darstellt:

    Behauptung fehlgeschlagen: x == 0

Leichtigkeitsrennen im Orbit
quelle
13

Wie ist die Einführung expliziter Konvertierungsoperatoren eine bahnbrechende Änderung? Die alte Version ist immer noch genauso "gültig" wie zuvor.

Ja, der Wechsel von operator void*() constzu explicit operator bool() constwird ein bahnbrechender Wechsel sein, aber nur, wenn er auf eine Weise verwendet wird, die an und für sich falsch ist. Konformer Code wird nicht beschädigt.

Eine weitere wichtige Änderung ist das Verbot der Verengung von Conversions während der aggregierten Initialisierung :

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

Bearbeiten : Nur erinnern, 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;
};
Xeo
quelle
Wenn Standardbibliotheksobjekte explizite Konvertierungen hinzugefügt haben, funktionieren vorhandene implizite Konvertierungen möglicherweise nicht mehr. Aber ich kann mir kein Szenario vorstellen, in dem die Konvertierung nicht gültig wäre und etwas Nützliches tun würde.
Dennis Zickefoose
Die Einführung ist eine bahnbrechende Änderung, da sie die bestehende ersetzen wirdoperator void* .
R. Martinho Fernandes
@ Tennis: Aaah, ich verstehe jetzt, was @ Martinho gemeint hat. Aber es wird nur eine bahnbrechende Veränderung sein, wenn die Leute es anders als beabsichtigt benutzt haben.
Xeo
"aber nur, wenn es auf eine Weise verwendet wird, die an und für sich falsch ist" - bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }In C ++ 03 ist daran nichts wirklich Falsches, aber in C ++ 11 ist es zu einem Fehler geworden. (Hinweis: GCC 4.9 hat noch operator void*() consthier, weshalb es den Code im C ++ 11-Modus akzeptiert.)
std::identity<T>wurde in C ++ 11 nicht entfernt, da es nicht Teil von C ++ 03 war. Es war im Entwurf für C ++ 11 kurz vorhanden und wurde vor der Standardisierung aus dem Entwurf entfernt.
Howard Hinnant
7

Es wurde viel darüber diskutiert implizite Schritte , die die Abwärtskompatibilität beeinträchtigen

( eine ältere Seite mit relevanter Diskussion )

Wenn Sie in den Kommentaren nachlesen, ist die implizite Verschiebungsrückgabe ebenfalls eine wichtige Änderung.

Ben Voigt
quelle
Das Ergebnis dieser Diskussionen ist, dass es in fast allen Fällen entfernt wurde. Gibt es irgendwelche Probleme mit dem, was noch übrig ist?
Dennis Zickefoose
@ Tennis: Ja. Ihre Frage wurde bereits auf dieser Folgeseite gestellt
Ben Voigt
Ahh, auf der mobilen Seite wurden die Kommentare nicht angezeigt. In jedem Fall ist dies der viel nützlichere Link ... Historische Kuriositäten des Standardisierungsprozesses sind nicht so relevant (es sei denn, Sie verwenden MSVC, von dem ich glaube, dass es diesen ersten Entwurf verwendet).
Dennis Zickefoose
@ Tennis: Ich denke du hast recht. Verschob die Links um einige in meiner Antwort.
Ben Voigt
Leider existiert cpp-next.com nicht mehr. Zum späteren Nachschlagen sind dies Seiten, die von web.archive.org gespeichert wurden: implizite Verschiebung, die die Abwärtskompatibilität beeinträchtigt, und eine ältere Seite mit relevanten Diskussionen .
Max Truxa
6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03: gültig.

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

Leichtigkeitsrennen im Orbit
quelle
2
@Xeo: Der Code ist in C ++ 03 gültig. Es ist ein Parameter mit Typ struct xund ohne Namen.
Ben Voigt
Ich hatte gehofft, jemanden zu erwischen. Ich wünschte nur, @Xeo hätte seinen Kommentar nicht so schnell gelöscht, da ich ihn nicht lesen konnte!
Leichtigkeitsrennen im Orbit
@Xeo: Ohne die Grammatik durchzuarbeiten, bin ich mir sicher, dass auto dort kein gültiges Schlüsselwort ist. Wenn es so wäre, würde es wahrscheinlich so funktionieren, wie Sie es erwarten, aber das ist wahrscheinlich sehr schwer richtig zu definieren.
Dennis Zickefoose
Sagen wir einfach, du hast mich erwischt. Die Struktur wurde buchstäblich ignoriert. :)
Xeo
@Tomalek: Xeo hatte zu Recht darauf hingewiesen, dass C ++ 03 kein implizites int hat.
Ben Voigt
-4

Sprachmerkmale

  1. Einheitliche und allgemeine Initialisierung mit {}
  2. Auto
  3. Verhinderung der Verengung
  4. constexpr
  5. Bereich basierend auf Schleife
  6. nullptr
  7. Aufzählungsklasse
  8. static_assert
  9. std :: initializer_list
  10. R-Wert-Referenzen (Verschiebungssemantik)
  11. >>
  12. Lambdas
  13. Variadische Vorlagen
  14. Typ- und Vorlagen-Aliase
  15. Unicode-Zeichen
  16. langer langer ganzzahliger Typ
  17. alignas und alignof
  18. decltype
  19. Rohe String-Literale
  20. Generalisierter POD
  21. Generalisierte Gewerkschaften
  22. Lokale Klassen als Vorlagenargumente
  23. Syntax des Suffix-Rückgabetyps
  24. [[trägt_abhängigkeit]] und [[noreturn]]
  25. noexcept Spezifizierer
  26. noexcept Operator.
  27. C99-Funktionen:
    • erweiterte integrale Typen
    • Verkettung der schmalen / breiten Zeichenfolge
    • _ _ STDC_HOSTED _ _
    • _Pragma (X)
    • Vararg-Makros und leere Makroargumente
  28. _ _ func _ _
  29. Inline-Namespaces
  30. Konstruktoren delegieren
  31. Initialisierer für Mitglieder in der Klasse
  32. Standard und löschen
  33. Explizite Konvertierungsoperatoren
  34. Benutzerdefinierte Literale
  35. Externe Vorlagen
  36. Standardvorlagenargumente für Funktionsvorlagen
  37. Konstruktoren erben
  38. überschreiben und endgültig
  39. Einfachere und allgemeinere SFINAE-Regel
  40. Speichermodell
  41. thread_local

Komponenten der Standardbibliothek

  1. initializer_list für Container
  2. Verschieben Sie die Semantik für Container
  3. forward_list
  4. Hash-Container
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. Ressourcenverwaltungszeiger
    • unique_ptr
    • shared_ptr
    • schwach_ptr
  6. Parallelitätsunterstützung
    • Faden
    • Mutexe
    • Schlösser
    • Bedingungsvariablen
  7. Unterstützung für Parallelität auf höherer Ebene
    • packaged_thread
    • Zukunft
    • versprechen
    • asynchron
  8. Tupel
  9. Regex
  10. Zufällige Zahlen
    • uniform_int_distribution
    • Normalverteilung
    • random_engine
    • etc.
  11. Ganzzahlige Typnamen wie int16_t, uint32_t und int_fast64_t
  12. Array
  13. Ausnahmen kopieren und erneut auslösen
  14. Systemfehler
  15. emplace () -Operationen für Container
  16. constexpr Funktionen
  17. Systematische Verwendung von Noexcept-Funktionen
  18. funktionieren und binden
  19. Konvertierung von Zeichenfolgen in numerische Werte
  20. Gültigkeitsbereich Allokatoren
  21. Typmerkmale
  22. Zeitdienstprogramme: Dauer und Zeitpunkt
  23. Verhältnis
  24. quick_exit
  25. Weitere Algorithmen wie move (), copy_if () und is_sorted ()
  26. Müllabfuhr ABI
  27. Atomics

Veraltete Funktionen

  1. Generierung des Kopierkonstruktors und der Kopierzuordnung für eine Klasse mit einem Destruktor.
  2. Weisen Sie einem Zeichen * ein Zeichenfolgenliteral zu.
  3. C ++ 98-Ausnahmespezifikation
    • nicht ausgenommener_Handler
    • set_unexpected
    • get_unexpected
    • unerwartet
  4. Funktionsobjekte und zugehörige Funktionen
  5. auto_ptr
  6. registrieren
  7. ++ auf einem Bool
  8. Export
  9. Casts im C-Stil
mustafagonul
quelle
3
Dies beantwortet die Frage nicht.