Quels changements de rupture sont introduits dans C ++ 11?


227

Je sais qu'au moins une des modifications de C ++ 11 qui entraînera l'arrêt de la compilation de l'ancien code: l'introduction de explicit operator bool()dans la bibliothèque standard, remplaçant les anciennes instances de operator void*(). Certes, le code que cela cassera est probablement un code qui n'aurait pas dû être valide en premier lieu, mais c'est quand même un changement de rupture: les programmes qui étaient valides ne le sont plus.

Y a-t-il d'autres changements de rupture?


1
Supprimer la signification du exportmot-clé? Je vais me chercher un manteau.
Steve Jessop

7
Vous savez, je ne dirais pas que le changement de conversion en booléen est un "changement révolutionnaire" ... plus comme un "changement punitif".
Xeo

4
Alors que toutes les formalités administratives nécessaires pour créer une telle union n'attendent que d'être tamponnées, bien sûr, pourquoi pas?
Dennis Zickefoose

3
@Xeo: mystream.good()n'est pas le même que bool(mystream)? good()est vrai si aucun indicateur n'est défini. bool(mystream)est toujours faux si seulement eofbitest défini. !mystream.fail()serait l'équivalent correct.
R. Martinho Fernandes

2
Note du modérateur : " Veuillez conserver les commentaires sur le sujet avec la question ou la réponse à portée de main. Lorsque vous discutez d'une question ou d'une réponse, la discussion doit porter uniquement sur cela, la question ou la réponse à portée de main. Le débat, en général, n'est pas constructif pour Stack Overflow. Antagoniser n'est certainement pas. "
Tim Post

Réponses:


178

Le FDIS a une section pour les incompatibilités, en annexe C.2"C ++ et ISO C ++ 2003".

Résumé, paraphrasant le FDIS ici, pour le rendre (mieux) approprié comme réponse SO. J'ai ajouté quelques exemples pour illustrer les différences.

Il y a quelques incompatibilités liées à la bibliothèque dont je ne connais pas exactement les implications, donc je laisse celles-ci aux autres pour les développer.

Langage de base


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

Nouveaux mots clés: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert et thread_local


Certains littéraux entiers plus grands que ce qui peut être représenté par long pourraient passer d'un type entier non signé à signé long long.


Un code C ++ 2003 valide qui utilise une division entière arrondit le résultat vers 0 ou vers l'infini négatif, tandis que C ++ 0x arrondit toujours le résultat vers 0.

(certes pas vraiment un problème de compatibilité pour la plupart des gens).


Le code C ++ 2003 valide qui utilise le mot-clé autocomme spécificateur de classe de stockage peut être invalide en C ++ 0x.


Le rétrécissement des conversions provoque des incompatibilités avec C ++ 03. Par exemple, le code suivant est valide en C ++ 2003 mais non valide dans la présente Norme internationale, car le double en int est une conversion restrictive:

int x[] = { 2.0 };

Les fonctions membres spéciales déclarées implicitement sont définies comme supprimées lorsque la définition implicite aurait été mal formée.

Un programme C ++ 2003 valide qui utilise l'une de ces fonctions membres spéciales dans un contexte où la définition n'est pas requise (par exemple, dans une expression qui n'est pas potentiellement évaluée) devient mal formé.

Exemple par moi:

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

De telles astuces de sizeof ont été utilisées par certains SFINAE, et doivent être modifiées maintenant :)


Les destructeurs déclarés par l'utilisateur ont une spécification d'exception implicite.

Exemple par moi:

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

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

Ce code appelle terminateen C ++ 0x, mais pas en C ++ 03. Parce que la spécification d'exception implicite de A::~AC ++ 0x est noexcept(true).


Une déclaration C ++ 2003 valide contenant exportest mal formée en C ++ 0x.


Une expression C ++ 2003 valide contenant >immédiatement suivie par une autre >peut maintenant être traitée comme fermant deux modèles.

En C ++ 03, >>serait toujours le jeton de l'opérateur de décalage.


Autoriser les appels de fonctions dépendants avec liaison interne.

Exemple par moi:

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

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

int main() { g(0); }

En C ++ 03, cela appelle f(long), mais en C ++ 0x, cela appelle f(int). Il convient de noter que dans C ++ 03 et C ++ 0x, les appels suivants f(B)(le contexte d'instanciation ne considère toujours que les déclarations de liaison externe).

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); }

La meilleure correspondance f(A)n'est pas prise, car elle n'a pas de liaison externe.


Modifications de la bibliothèque

Le code C ++ 2003 valide qui utilise tous les identificateurs ajoutés à la bibliothèque standard C ++ de C ++ 0x peut ne pas compiler ou produire des résultats différents dans la présente Norme internationale.


Un code C ++ 2003 valide indiquant que les #includesen - têtes avec les noms des nouveaux en-têtes de bibliothèque standard C ++ 0x peuvent être invalides dans la présente Norme internationale.


Le code C ++ 2003 valide qui a été compilé en s'attendant à ce que le swap soit <algorithm>inclus doit inclure à la place<utility>


L'espace de noms global posixest désormais réservé à la normalisation.


Valide C ++ code 2003 qui définit override, final, carries_dependencyou noreturnsous forme de macros est invalide dans C ++ 0x.


"Autoriser les appels dépendants de fonctions avec liaison interne." Pourriez-vous expliquer la différence entre vos deux exemples? Il me manque clairement quelque chose.
Dennis Zickefoose

@Dennis, le changement a été introduit par open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 . Bien qu'ils ne commentent pas le fait, le "contexte d'instanciation" ne comprend toujours que "l'ensemble des déclarations avec liaison externe déclarées avant le point d'instanciation de la spécialisation du modèle dans la même unité de traduction". Ainsi, la modification qu'ils ont apportée affecte uniquement la recherche dans le contexte de définition.
Johannes Schaub - litb

Dans mon premier exemple donné, la fonction de liaison interne était visible et trouvée dans le contexte de définition du modèle. Dans mon deuxième exemple, la fonction de liaison interne devrait faire partie du contexte d'instanciation à trouver. Mais comme ce n'est pas le cas, il est introuvable.
Johannes Schaub - litb

Soit dit en passant, je pense que le seul cas où il est sûr pour un contexte de définition de modèle de trouver une fonction avec une liaison interne est lorsque la spécialisation de modèle de fonction n'est instanciée explicitement que dans un seul TU (où le modèle est défini), et que tous les autres TU s'appuient sur cette instanciation explicite. Dans tous les autres cas (où les autres TU instancieraient eux-mêmes la spécialisation), vous violeriez l'ODR en faisant en sorte que la définition de modèle utilise une fonction différente (liaison interne) à chaque fois.
Johannes Schaub - litb

Donc, je ne sais pas pourquoi ils ont gardé la restriction sur le contexte d'instanciation - il n'y aurait qu'une seule instanciation (explicite), et cette instanciation utiliserait des fonctions de liaison internes trouvées dans le contexte d'instanciation du TU instanciant. Tout comme pour le contexte de définition. Soit dit en passant, je pense que si nous l'avions encore export, alors je pense que les autres TU n'auraient pas besoin de s'appuyer sur l'instanciation explicite, mais pourraient instancier le modèle eux-mêmes. Ensuite, cela ferait une différence que les fonctions de liaison interne soient visibles ou non dans le contexte d'instanciation.
Johannes Schaub - litb

28

La signification du mot clé auto a changé.


9
Si vous avez utilisé le automot clé, quelque chose ne va pas avec votre code. Pourquoi diable l'utiliseriez-vous?
Elazar Leibovich

Ce n'est pas un changement de rupture . Toute utilisation valide de C ++ 03 autoreste valide en C ++ 11.
Drew Dormann

11
@DrewDormann int main() { auto int i = 0; return i; }est parfaitement valide en C ++ 03, mais une erreur de syntaxe en C ++ 11. Le seul avertissement que je peux obtenir des compilateurs pour le donner en mode C ++ 03 est un avertissement sur la compatibilité.

24

Briser le changement?

Eh bien, pour une chose, si vous avez utilisé decltype, constexpr, nullptr, etc. comme identifiants alors vous pouvez être en difficulté ...


21

Certaines incompatibilités de base qui ne sont pas couvertes par la section des incompatibilités:


C ++ 0x traite le nom de classe injecté comme un modèle, si le nom est passé comme argument à un paramètre de modèle de modèle, et comme un type s'il est passé à un paramètre de type de modèle.

Un code C ++ 03 valide peut se comporter différemment s'il repose sur le nom de classe injecté pour être toujours un type dans ces scénarios. Exemple de code tiré de mon PR clang

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();
}

En C ++ 03, le code appelle la seconde gfois.


C ++ 0x fait que certains noms qui étaient dépendants en C ++ 03 sont désormais non dépendants. Et nécessite la recherche de noms pour les noms qualifiés non dépendants qui font référence aux membres du modèle de classe actuel à répéter lors de l'instanciation, et nécessite la vérification que ces noms recherchent de la même manière que dans le contexte de définition du modèle.

Le code C ++ 03 valide qui dépend de la règle de dominance peut désormais ne plus être compilé à cause de ce changement.

Exemple:

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(); }

Ce code C ++ 03 valide qui appelle A<int>::fn'est pas valide en C ++ 0x, car la recherche de nom lors de l'instanciation trouvera, A<int>::fpar opposition àB::f , provoquant un conflit avec la recherche at-definition.

À ce stade, il n'est pas clair s'il s'agit d'un défaut du FDIS. Le comité en est conscient et évaluera la situation.


Une déclaration using où la dernière partie est identique à l'identificateur dans la dernière partie du qualificatif du nom qualifié désignant une classe de base, cette déclaration using nomme désormais le constructeur, au lieu des membres portant ce nom.

Exemple:

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

L'exemple de code ci-dessus est bien formé en C ++ 03, mais mal formé en C ++ 0x, car il A::Best toujours inaccessible en main.


14

L'échec d'extraction de flux est traité différemment.

Exemple

#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
}

Modifier la proposition

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

Référence standard

[C++03: 22.2.2.1.2/11]: Le résultat du traitement de l'étape 2 peut être l'un des

  • Une séquence de caractères a été accumulée à l'étape 2 qui est convertie (selon les règles de scanf) en une valeur du type de val. Cette valeur est stockée dans valet ios_base::goodbitest stockée dans err.
  • La séquence de caractères accumulée à l'étape 2 aurait provoqué scanfun échec d'entrée. ios_base::failbitest affecté à err. [ed: Rien n'est stocké dans val.]

[C++11: 22.4.2.1.2/3]: [..] La valeur numérique à stocker peut être l'une des suivantes:

  • zéro, si la fonction de conversion ne parvient pas à convertir le champ entier . ios_base::failbitest affecté à err.
  • la valeur représentative la plus positive, si le champ représente une valeur trop grande positive pour être représentée val. ios_base::failbitest affecté à err.
  • la valeur représentable la plus négative ou zéro pour un type d'entier non signé, si le champ représente une valeur trop grande négative pour être représentée val. ios_base::failbitest affecté à err.
  • la valeur convertie, sinon.

La valeur numérique résultante est stockée dans val.

Implémentations

  • GCC 4.8 sort correctement pour C ++ 11 :

    Échec de l'assertion `x == -1 '

  • GCC 4.5-4.8 toutes les sorties pour C ++ 03 ce qui semble être un bug:

    Échec de l'assertion `x == -1 '

  • Visual C ++ 2008 Express affiche correctement pour C ++ 03:

    Échec de l'assertion: x == 0

  • Visual C ++ 2012 Express affiche de manière incorrecte pour C ++ 11, ce qui semble être un problème de statut d'implémentation:

    Échec de l'assertion: x == 0


13

En quoi l'introduction d'opérateurs de conversion explicites est-elle un changement de rupture? L'ancienne version sera toujours aussi "valide" qu'auparavant.

Oui, le changement de operator void*() constàexplicit operator bool() const sera un changement de rupture, mais seulement s'il est utilisé d'une manière qui est mauvaise en soi. Le code conforme ne sera pas rompu.

Maintenant, un autre changement de rupture est l'interdiction de réduire les conversions lors de l'initialisation globale :

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

Edit : N'oubliez pas, std::identity<T>sera supprimé en C ++ 0x (voir la note). C'est une structure de commodité pour rendre les types dépendants. Étant donné que la structure ne fait vraiment pas grand-chose, cela devrait le corriger:

template<class T>
struct identity{
  typedef T type;
};

Si des conversions explicites ont été ajoutées aux objets de bibliothèque standard, les conversions implicites existantes peuvent cesser de fonctionner. Mais je ne peux pas imaginer un scénario où la conversion ne serait pas valide et ferait quelque chose d'utile.
Dennis Zickefoose

L'introduction est un changement de rupture car elle va remplacer l'existant operator void*.
R. Martinho Fernandes

@Dennis: Aaah, je vois maintenant ce que @Martinho voulait dire. Mais ce ne sera un changement de rupture que si les gens l'utilisent autrement que prévu.
Xeo

"mais seulement s'il est utilisé d'une manière qui est fausse en lui-même et en dehors de lui-même" - bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }Il n'y a vraiment rien de mal à cela en C ++ 03, pourtant c'est devenu une erreur en C ++ 11. (Remarque: GCC 4.9 est toujours operator void*() constlà, c'est pourquoi il accepte le code en mode C ++ 11.)

std::identity<T>n'a pas été supprimé en C ++ 11, car il ne faisait pas partie de C ++ 03. Il existait brièvement dans le projet de C ++ 11 et a été supprimé du projet avant la normalisation.
Howard Hinnant


7

Il y a eu beaucoup de discussions sur les mouvements implicites brisant la compatibilité descendante

( une page plus ancienne avec une discussion pertinente )

Si vous lisez les commentaires, le retour de mouvement implicite est également un changement de rupture.


Le résultat de ces discussions est qu'il a été supprimé dans presque tous les cas. Y a-t-il des problèmes avec ce qui reste?
Dennis Zickefoose

@Dennis: Oui. Votre question a déjà été posée, répondue et débattue à mort sur cette page de suivi
Ben Voigt

Ahh, la page mobile n'a pas montré les commentaires. Quoi qu'il en soit, c'est le lien beaucoup plus utile ... Les bizarreries historiques du processus de normalisation ne sont pas si pertinentes (sauf si vous utilisez MSVC, qui, je crois, utilise cette première version).
Dennis Zickefoose

@ Dennis: Je pense que vous avez raison. Déplacé les liens autour de certains dans ma réponse.
Ben Voigt

Malheureusement, cpp-next.com n'existe plus. Pour référence future, ce sont des pages enregistrées par web.archive.org: déplacement implicite rompant la compatibilité descendante et une page plus ancienne avec une discussion pertinente .
Max Truxa

6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03: valide.

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


2
@Xeo: Le code est valide en C ++ 03. C'est un paramètre avec type struct xet sans nom.
Ben Voigt

J'espérais rattraper quelqu'un. Je souhaite seulement que @Xeo n'ait pas été si rapide pour supprimer son commentaire, car je n'ai pas pu le lire!
Courses de légèreté en orbite le

@Xeo: Sans fouiller dans la grammaire, je suis sûr que auto n'est tout simplement pas un mot clé valide. Si c'était le cas, cela fonctionnerait probablement comme prévu, mais c'est probablement très difficile à définir correctement.
Dennis Zickefoose

Disons que tu m'as rattrapé. Il a littéralement ignoré la structure. :)
Xeo

@Tomalek: Xeo avait souligné à juste titre que C ++ 03 n'a pas d'int implicite.
Ben Voigt

-4

Caractéristiques linguistiques

  1. Initialisation uniforme et générale à l'aide de {}
  2. auto
  3. Prévention du rétrécissement
  4. constexpr
  5. Plage basée sur la boucle
  6. nullptr
  7. classe énumération
  8. static_assert
  9. std :: initializer_list
  10. Références Rvalue (déplacer la sémantique)
  11. >>
  12. Lambdas
  13. Modèles variadic
  14. Type et alias de modèle
  15. Caractères Unicode
  16. type entier long long
  17. alignas et alignof
  18. decltype
  19. Littéraux de chaîne bruts
  20. POD généralisé
  21. Unions généralisées
  22. Classes locales comme arguments de modèle
  23. Syntaxe du type de retour de suffixe
  24. [[carry_dependency]] et [[noreturn]]
  25. sans spécificateur
  26. aucun opérateur sauf.
  27. Caractéristiques du C99:
    • types intégraux étendus
    • concaténation de chaîne étroite / large
    • _ _ STDC_HOSTED _ _
    • _Pragma (X)
    • macros vararg et arguments de macro vides
  28. _ _ func _ _
  29. Espaces de noms en ligne
  30. Déléguer des constructeurs
  31. Initialiseurs de membres en classe
  32. par défaut et supprimer
  33. Opérateurs de conversion explicites
  34. Littéraux définis par l'utilisateur
  35. Modèles externes
  36. Arguments de modèle par défaut pour les modèles de fonction
  37. Hériter des constructeurs
  38. remplacement et final
  39. Règle SFINAE plus simple et plus générale
  40. Modèle de mémoire
  41. thread_local

Composants de bibliothèque standard

  1. initializer_list pour les conteneurs
  2. Déplacer la sémantique des conteneurs
  3. liste_en avant
  4. Conteneurs de hachage
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. Pointeurs de gestion des ressources
    • unique_ptr
    • shared_ptr
    • faiblesse_ptr
  6. Prise en charge de la concurrence
    • fil
    • mutex
    • serrures
    • variables de condition
  7. Prise en charge de l'accès simultané de niveau supérieur
    • packaged_thread
    • futur
    • promettre
    • async
  8. tuples
  9. regex
  10. Nombres aléatoires
    • uniform_int_distribution
    • distribution normale
    • random_engine
    • etc.
  11. Noms de type entier, tels que int16_t, uint32_t et int_fast64_t
  12. tableau
  13. Copie et renvoi des exceptions
  14. erreur système
  15. opérations emplace () pour les conteneurs
  16. fonctions constexpr
  17. Utilisation systématique des fonctions noexcept
  18. fonctionner et lier
  19. Conversion de chaînes en valeurs numériques
  20. Allocateurs de portée
  21. Traits de type
  22. Utilitaires de temps: durée et point_heure
  23. rapport
  24. quick_exit
  25. Plus d'algorithmes, tels que move (), copy_if () et is_sorted ()
  26. Collecte des ordures ABI
  27. atomique

Fonctions obsolètes

  1. Génération du constructeur de copie et de l'affectation de copie pour une classe avec un destructeur.
  2. Attribuez un littéral de chaîne à un caractère *.
  3. Spécification d'exception C ++ 98
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • inattendu
  4. Objets fonction et fonctions associées
  5. auto_ptr
  6. S'inscrire
  7. ++ sur un bool
  8. exportation
  9. Moulages de style C

3
Cela ne répond pas à la question.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.