Sim, existem várias alterações que farão com que o mesmo código resulte em comportamento diferente entre C ++ 03 e C ++ 11. As diferenças das regras de seqüenciamento fazem algumas mudanças interessantes, incluindo um comportamento indefinido anteriormente se tornando bem definido.
1. múltiplas mutações da mesma variável em uma lista de inicializadores
Um caso de canto muito interessante teria várias mutações da mesma variável em uma lista de inicializadores, por exemplo:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
No C ++ 03 e no C ++ 11, isso está bem definido, mas a ordem de avaliação no C ++ 03 não é especificada, mas no C ++ 11 elas são avaliadas na ordem em que aparecem . Portanto, se compilarmos usando clang
no modo C ++ 03, forneça o seguinte aviso ( veja ao vivo ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
mas não fornece um aviso no C ++ 11 ( veja ao vivo ).
2. Novas regras de seqüenciamento tornam i = ++ i + 1; bem definido em C ++ 11
As novas regras de seqüenciamento adotadas após o C ++ 03 significam que:
int i = 0 ;
i = ++ i + 1;
não é mais um comportamento indefinido no C ++ 11, isso é coberto no relatório de defeitos 637. Regras e exemplo de seqüenciamento discordam
3. Novas regras de seqüenciamento também tornam ++++ i; bem definido em C ++ 11
As novas regras de seqüenciamento adotadas após o C ++ 03 significam que:
int i = 0 ;
++++i ;
não é mais um comportamento indefinido no C ++ 11.
4. Deslocamentos à esquerda assinados um pouco mais sensíveis
Os rascunhos posteriores do C ++ 11 incluem o N3485
link abaixo, que corrigiu o comportamento indefinido de mudar um bit para o bit de sinal ou ultrapassá-lo . Isso também é coberto no relatório de defeitos 1457 . Howard Hinnant comentou sobre o significado dessa alteração no thread. O deslocamento para a esquerda (<<) é um comportamento indefinido de número inteiro negativo no C ++ 11? .
5. As funções constexpr podem ser tratadas como expressões constantes de tempo de compilação em C ++ 11
O C ++ 11 introduziu funções constexpr que:
O especificador constexpr declara que é possível avaliar o valor da função ou variável em tempo de compilação. Tais variáveis e funções podem ser usadas onde apenas expressões de constante de tempo de compilação são permitidas.
enquanto o C ++ 03 não possui o recurso constexpr , não precisamos usar explicitamente a palavra-chave constexpr, pois a biblioteca padrão fornece muitas funções no C ++ 11 como constexpr . Por exemplo, std :: numeric_limits :: min . O que pode levar a um comportamento diferente, por exemplo:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
O uso clang
no C ++ 03 causa x
uma matriz de comprimento variável, que é uma extensão e gera o seguinte aviso:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
enquanto em C ++ 11 std::numeric_limits<unsigned int>::min()+2
é uma expressão constante de tempo de compilação e não requer a extensão VLA.
6. No C ++ 11, as exceções de exceção são geradas implicitamente para seus destruidores
Como no destruidor definido pelo usuário do C ++ 11 tem noexcept(true)
especificação implícita, conforme explicado em noexcept destructors, isso significa que o seguinte programa:
#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";
}
No C ++ 11 será chamado, std::terminate
mas será executado com êxito no C ++ 03.
7. No C ++ 03, os argumentos do modelo não podiam ter ligação interna
Isso é abordado muito bem em Por que std :: sort não aceita classes Compare declaradas em uma função . Portanto, o código a seguir não deve funcionar no 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;
}
}
mas atualmente clang
permite esse código no modo C ++ 03 com um aviso, a menos que você use -pedantic-errors
sinalizador, que é meio nojento, veja ao vivo .
8. >> não está mais mal formado ao fechar vários modelos
Usar >>
para fechar vários modelos não está mais mal formado, mas pode levar ao código com resultados diferentes em C ++ 03 e C + 11. O exemplo abaixo é retirado de colchetes angulares retos e compatibilidade com versões anteriores :
#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 o resultado em C ++ 03 é:
0
3
e em C ++ 11:
0
0
9. O C ++ 11 altera alguns dos construtores std :: vector
O código levemente modificado desta resposta mostra que, usando o seguinte construtor de std :: vector :
std::vector<T> test(1);
produz resultados diferentes em 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. Restringir conversões em inicializadores agregados
No C ++ 11, uma conversão restrita nos inicializadores agregados é mal formada e parece gcc
permitir isso no C ++ 11 e no C ++ 03, embora forneça um aviso por padrão no C ++ 11:
int x[] = { 2.0 };
Isso é coberto no rascunho da seção padrão do C ++ 11, parágrafo 3 de 8.5.4
inicialização da lista :
A inicialização da lista de um objeto ou referência do tipo T é definida da seguinte maneira:
e contém o seguinte marcador ( ênfase minha ):
Caso contrário, se T for um tipo de classe, os construtores serão considerados. Os construtores aplicáveis são enumerados e o melhor é escolhido através da resolução de sobrecarga (13.3, 13.3.1.7). Se uma conversão restrita (veja abaixo) for necessária para converter qualquer um dos argumentos, o programa será mal formado
Isto e muito mais exemplo são abrangidos no projecto de C ++ padrão secção annex C.2
C ++ e ISO C ++ 2003 . Também inclui:
Novos tipos de literais de cadeia [...] Especificamente, macros denominadas R, u8, u8R, u, uR, U, UR ou LR não serão expandidas quando adjacentes a uma literal de cadeia, mas serão interpretadas como parte da literal de cadeia. . Por exemplo
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
Suporte a cadeia literal definido pelo usuário [...] Anteriormente, o nº 1 consistiria em dois tokens de pré-processamento separados e a macro _x teria sido expandida. Nesse padrão internacional, o número 1 consiste em um único tokens de pré-processamento, para que a macro não seja expandida.
#define _x "there"
"hello"_x // #1
Especifique o arredondamento para resultados do código inteiro / e% [...] 2003 que usa divisão inteira arredonda o resultado para 0 ou para o infinito negativo, enquanto que este Padrão Internacional sempre arredonda o resultado para 0.
Complexidade das funções de membro size () agora constantes [...] Algumas implementações de contêineres que estão em conformidade com o C ++ 2003 podem não estar em conformidade com os requisitos de tamanho () especificados nesta Norma. Ajustar contêineres como std :: list aos requisitos mais rígidos pode exigir alterações incompatíveis.
Alterar classe base de std :: ios_base :: fail [...] std :: ios_base :: fail não é mais derivado diretamente de std :: exception, mas agora é derivado de std :: system_error, que por sua vez é derivado de std :: runtime_error. O código C ++ 2003 válido que assume que std :: ios_base :: fault é derivado diretamente de std :: exception pode ser executado de maneira diferente neste Padrão Internacional.
auto
poderia resultar em uma situação como esta