Oui, il existe un certain nombre de modifications qui entraîneront le même code à entraîner un comportement différent entre C ++ 03 et C ++ 11. Les différences de règles de séquençage entraînent des changements intéressants, dont certains comportements auparavant non définis devenant bien définis.
1. plusieurs mutations de la même variable dans une liste d'initialisation
Un cas d'angle très intéressant serait de multiples mutations de la même variable dans une liste d'initialisation, par exemple:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
En C ++ 03 et C ++ 11, cela est bien défini mais l' ordre d'évaluation en C ++ 03 n'est pas spécifié mais en C ++ 11, ils sont évalués dans l'ordre dans lequel ils apparaissent . Donc, si nous compilons en utilisant clang
en mode C ++ 03, il fournit l'avertissement suivant ( voir en direct ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
mais ne fournit pas d'avertissement en C ++ 11 ( voir en direct ).
2. De nouvelles règles de séquencement font i = ++ i + 1; bien défini en C ++ 11
Les nouvelles règles de séquençage adoptées après C ++ 03 signifient que:
int i = 0 ;
i = ++ i + 1;
n'est plus un comportement indéfini en C ++ 11, cela est traité dans le rapport de défauts 637. Règles de séquencement et exemple en désaccord
3. De nouvelles règles de séquençage font également ++++ i; bien défini en C ++ 11
Les nouvelles règles de séquençage adoptées après C ++ 03 signifient que:
int i = 0 ;
++++i ;
n'est plus un comportement indéfini en C ++ 11.
4. Décalages à gauche légèrement plus sensibles et signés
Les versions ultérieures de C ++ 11 incluent N3485
que je lie ci-dessous fixe le comportement indéfini de décaler un bit dans ou après le bit de signe . Ceci est également couvert dans le rapport de défauts 1457 . Howard Hinnant a commenté la signification de ce changement dans le fil de discussion sur Est-ce que le décalage vers la gauche (<<) est un comportement négatif entier non défini en C ++ 11? .
5. Les fonctions constexpr peuvent être traitées comme des expressions de constante de temps de compilation en C ++ 11
C ++ 11 a introduit des fonctions constexpr qui:
Le spécificateur constexpr déclare qu'il est possible d'évaluer la valeur de la fonction ou de la variable au moment de la compilation. Ces variables et fonctions peuvent ensuite être utilisées lorsque seules les expressions de constante de temps de compilation sont autorisées.
tandis que C ++ 03 n'a pas la fonctionnalité constexpr , nous n'avons pas à utiliser explicitement le mot clé constexpr car la bibliothèque standard fournit de nombreuses fonctions en C ++ 11 comme constexpr . Par exemple std :: numeric_limits :: min . Ce qui peut conduire à des comportements différents, par exemple:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
L'utilisation clang
en C ++ 03 entraînera x
un tableau de longueur variable, qui est une extension et générera l'avertissement suivant:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
en C ++ 11 std::numeric_limits<unsigned int>::min()+2
est une expression de constante de temps de compilation et ne nécessite pas l'extension VLA.
6. En C ++ 11, aucune spécification d'exception n'est générée implicitement pour vos destructeurs
Étant donné qu'en C ++ 11, le destructeur défini par l'utilisateur a une noexcept(true)
spécification implicite comme expliqué dans noexcept destructors, cela signifie que le programme suivant:
#include <iostream>
#include <stdexcept>
struct S
{
~S() { throw std::runtime_error(""); } // bad, but acceptable
};
int main()
{
try { S s; }
catch (...) {
std::cerr << "exception occurred";
}
std::cout << "success";
}
En C ++ 11 appellera std::terminate
mais s'exécutera avec succès en C ++ 03.
7. En C ++ 03, les arguments de modèle ne pouvaient pas avoir de liaison interne
Ceci est bien décrit dans Pourquoi std :: sort n'accepte pas les classes Compare déclarées dans une fonction . Le code suivant ne devrait donc pas fonctionner en C ++ 03:
#include <iostream>
#include <vector>
#include <algorithm>
class Comparators
{
public:
bool operator()(int first, int second)
{
return first < second;
}
};
int main()
{
class ComparatorsInner : public Comparators{};
std::vector<int> compares ;
compares.push_back(20) ;
compares.push_back(10) ;
compares.push_back(30) ;
ComparatorsInner comparatorInner;
std::sort(compares.begin(), compares.end(), comparatorInner);
std::vector<int>::iterator it;
for(it = compares.begin(); it != compares.end(); ++it)
{
std::cout << (*it) << std::endl;
}
}
mais clang
autorise actuellement ce code en mode C ++ 03 avec un avertissement, sauf si vous utilisez un -pedantic-errors
indicateur, ce qui est un peu icky, voyez-le en direct .
8. >> n'est plus mal formé lors de la fermeture de plusieurs modèles
Utiliser >>
pour fermer plusieurs modèles n'est plus mal formé mais peut conduire à du code avec des résultats différents en C ++ 03 et C + 11. L'exemple ci-dessous est tiré des supports à angle droit et de la compatibilité descendante :
#include <iostream>
template<int I> struct X {
static int const c = 2;
};
template<> struct X<0> {
typedef int c;
};
template<typename T> struct Y {
static int const c = 3;
};
static int const c = 4;
int main() {
std::cout << (Y<X<1> >::c >::c>::c) << '\n';
std::cout << (Y<X< 1>>::c >::c>::c) << '\n';
}
et le résultat en C ++ 03 est:
0
3
et en C ++ 11:
0
0
9. C ++ 11 change certains des constructeurs std :: vector
Le code légèrement modifié de cette réponse montre que l'utilisation du constructeur suivant de std :: vector :
std::vector<T> test(1);
produit des résultats différents en C ++ 03 et C ++ 11:
#include <iostream>
#include <vector>
struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};
int main()
{
std::vector<T> test(1);
bool is_cpp11 = !test[0].flag;
std::cout << is_cpp11 << std::endl ;
}
10. Rétrécissement des conversions dans les initialiseurs globaux
En C ++ 11, une conversion de rétrécissement dans les initialiseurs d'agrégation est mal formée et il semble que gcc
cela soit possible en C ++ 11 et C ++ 03 bien qu'elle fournisse un avertissement par défaut en C ++ 11:
int x[] = { 2.0 };
Ceci est traité dans le projet de section standard d' 8.5.4
initialisation de la liste C ++ 11 paragraphe 3 :
L'initialisation de liste d'un objet ou d'une référence de type T est définie comme suit:
et contient la puce suivante (c'est moi qui souligne ):
Sinon, si T est un type de classe, les constructeurs sont pris en compte. Les constructeurs applicables sont énumérés et le meilleur est choisi par résolution de surcharge (13.3, 13.3.1.7). Si une conversion de rétrécissement (voir ci-dessous) est nécessaire pour convertir l'un des arguments, le programme est mal formé
Cette instance et bien d'autres sont traitées dans le projet de section standard annex C.2
C ++ C ++ et ISO C ++ 2003 . Il comprend également:
Nouveaux types de littéraux de chaîne [...] Plus précisément, les macros nommées R, u8, u8R, u, uR, U, UR ou LR ne seront pas développées lorsqu'elles sont adjacentes à un littéral de chaîne mais seront interprétées comme faisant partie du littéral de chaîne . Par exemple
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
Prise en charge des chaînes littérales définies par l'utilisateur [...] Auparavant, le n ° 1 aurait consisté en deux jetons de prétraitement distincts et la macro _x aurait été étendue. Dans la présente Norme internationale, # 1 consiste en un seul jeton de prétraitement, de sorte que la macro n'est pas développée.
#define _x "there"
"hello"_x // #1
Spécifiez l'arrondi pour les résultats du code entier / et% [...] 2003 qui utilise la division entière arrondit le résultat vers 0 ou vers l'infini négatif, tandis que la présente Norme internationale arrondit toujours le résultat vers 0.
La complexité des fonctions membres size () est désormais constante [...] Certaines implémentations de conteneurs conformes à C ++ 2003 peuvent ne pas être conformes aux exigences size () spécifiées dans la présente Norme internationale. L'ajustement de conteneurs tels que std :: list aux exigences plus strictes peut nécessiter des modifications incompatibles.
Modifier la classe de base de std :: ios_base :: failure [...] std :: ios_base :: failure n'est plus dérivé directement de std :: exception, mais est désormais dérivé de std :: system_error, qui à son tour est dérivé de std :: runtime_error. Un code C ++ 2003 valide qui suppose que std :: ios_base :: failure est dérivé directement de std :: exception peut s'exécuter différemment dans la présente Norme internationale.
auto
pourrait entraîner une situation comme celle-ci