Sì, ci sono un numero di modifiche che causeranno lo stesso codice a comportare comportamenti diversi tra C ++ 03 e C ++ 11. Le differenze delle regole di sequenziamento rendono alcune modifiche interessanti tra cui alcuni comportamenti precedentemente non definiti che diventano ben definiti.
1. mutazioni multiple della stessa variabile all'interno di un elenco di inizializzatori
Un caso d'angolo molto interessante sarebbe più mutazioni della stessa variabile all'interno di un elenco di inizializzatori, ad esempio:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
In C ++ 03 e C ++ 11 questo è ben definito, ma l' ordine di valutazione in C ++ 03 non è specificato ma in C ++ 11 sono valutati nell'ordine in cui appaiono . Quindi, se compiliamo utilizzando clang
in modalità C ++ 03, fornisce il seguente avviso ( vederlo dal vivo ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
ma non fornisce un avviso in C ++ 11 ( vederlo dal vivo ).
2. Le nuove regole di sequenziamento rendono i = ++ i + 1; ben definito in C ++ 11
Le nuove regole di sequenziamento adottate dopo C ++ 03 significano che:
int i = 0 ;
i = ++ i + 1;
non è più un comportamento indefinito in C ++ 11, questo è trattato nel rapporto sui difetti 637. Le regole di sequenza e l'esempio non sono d'accordo
3. Nuove regole di sequenziamento rendono anche ++++ i; ben definito in C ++ 11
Le nuove regole di sequenziamento adottate dopo C ++ 03 significano che:
int i = 0 ;
++++i ;
non è più un comportamento indefinito in C ++ 11.
4. Spostamenti a sinistra firmati leggermente più sensibili
Le bozze successive di C ++ 11 includono N3485
quali collegamenti sotto risolto il comportamento indefinito di spostamento di 1 bit dentro o oltre il bit di segno . Questo è anche coperto dal rapporto sui difetti 1457 . Howard Hinnant ha commentato il significato di questo cambiamento nel thread su Spostamento a sinistra (<<) un comportamento intero negativo non definito in C ++ 11? .
5. Le funzioni constexpr possono essere trattate come espressioni costanti di tempo di compilazione in C ++ 11
C ++ 11 ha introdotto le funzioni constexpr che:
Lo specificatore constexpr dichiara che è possibile valutare il valore della funzione o della variabile in fase di compilazione. Tali variabili e funzioni possono quindi essere utilizzate laddove sono consentite solo espressioni di costanti di tempo di compilazione.
mentre C ++ 03 non ha la funzione constexpr , non è necessario utilizzare esplicitamente la parola chiave constexpr poiché la libreria standard fornisce molte funzioni in C ++ 11 come constexpr . Ad esempio std :: numeric_limits :: min . Che può portare a comportamenti diversi, ad esempio:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
Usando clang
in C ++ 03 questo causerà x
un array di lunghezza variabile, che è un'estensione e genererà il seguente avviso:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
mentre in C ++ 11 std::numeric_limits<unsigned int>::min()+2
è un'espressione costante di compilazione e non richiede l'estensione VLA.
6. In C ++ 11 le eccezioni senza eccezioni sono generate implicitamente per i distruttori
Poiché in C ++ 11 il distruttore definito dall'utente ha una noexcept(true)
specifica implicita come spiegato nei distruttori noexcept , significa che il seguente programma:
#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";
}
In C ++ 11 chiamerà std::terminate
ma verrà eseguito correttamente in C ++ 03.
7. In C ++ 03, gli argomenti del modello non potevano avere un collegamento interno
Questo è ben spiegato in Perché std :: sort non accetta le classi di confronto dichiarate all'interno di una funzione . Quindi il codice seguente non dovrebbe funzionare in 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;
}
}
ma attualmente clang
consente questo codice in modalità C ++ 03 con un avviso a meno che non si usi -pedantic-errors
flag, che è un po 'icky, vederlo dal vivo .
8. >> non è più mal formato quando si chiudono più modelli
L'uso >>
per chiudere più modelli non è più mal formato ma può portare a codice con risultati diversi in C ++ 03 e C + 11. L'esempio seguente è tratto dalle parentesi ad angolo retto e dalla compatibilità con le versioni precedenti :
#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';
}
e il risultato in C ++ 03 è:
0
3
e in C ++ 11:
0
0
9. C ++ 11 modifica alcuni dei costruttori std :: vector
Il codice leggermente modificato da questa risposta mostra che usando il seguente costruttore da std :: vector :
std::vector<T> test(1);
produce risultati diversi in C ++ 03 e 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. Restringere le conversioni negli inizializzatori aggregati
In C ++ 11 una conversione restrittiva negli inizializzatori aggregati è mal formata e sembra gcc
consentire ciò sia in C ++ 11 che in C ++ 03 sebbene fornisca un avviso di default in C ++ 11:
int x[] = { 2.0 };
Questo è trattato nella bozza della sezione standard C ++ 11 8.5.4
Inizializzazione elenco paragrafo 3 :
L'inizializzazione dell'elenco di un oggetto o un riferimento di tipo T è definita come segue:
e contiene il seguente punto elenco (il mio accento è mio ):
Altrimenti, se T è un tipo di classe, vengono considerati i costruttori. Vengono elencati i costruttori applicabili e il migliore viene scelto tramite risoluzione di sovraccarico (13.3, 13.3.1.7). Se è richiesta una conversione restrittiva (vedi sotto) per convertire uno qualsiasi degli argomenti, il programma è mal formato
Questo e molti altri sono coperti esempio nel progetto C ++ standard di sezione annex C.2
C ++ e C ++ ISO 2003 . Include anche:
Nuovi tipi di valori letterali di stringa [...] In particolare, le macro denominate R, u8, u8R, u, uR, U, UR o LR non verranno espanse quando sono adiacenti a un valore letterale di stringa ma verranno interpretate come parte del valore letterale di stringa . Per esempio
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
Supporto stringa letterale definito dall'utente [...] In precedenza, il numero 1 era costituito da due token di preelaborazione separati e la macro _x sarebbe stata espansa. In questo standard internazionale, il numero 1 consiste in un singolo token di preelaborazione, quindi la macro non viene espansa.
#define _x "there"
"hello"_x // #1
Specificare l'arrotondamento per i risultati del codice intero / e% [...] 2003 che utilizza la divisione di numeri interi arrotonda il risultato verso 0 o verso l'infinito negativo, mentre questo standard internazionale arrotonda sempre il risultato verso 0.
La complessità delle funzioni membro size () ora è costante [...] Alcune implementazioni di container conformi a C ++ 2003 potrebbero non essere conformi ai requisiti size () specificati in questo standard internazionale. Adattare i contenitori come std :: list ai requisiti più severi può richiedere modifiche incompatibili.
Cambia la classe base di std :: ios_base :: failure [...] std :: ios_base :: failure non deriva più direttamente da std :: exception, ma ora deriva da std :: system_error, che a sua volta deriva da std :: runtime_error. Il codice C ++ 2003 valido che presuppone che std :: ios_base :: failure sia derivato direttamente da std :: exception può essere eseguito in modo diverso in questo standard internazionale.
auto
potrebbe tradursi in una situazione come questa