Quais mudanças recentes são introduzidas no C ++ 11?


227

Eu sei que pelo menos uma das alterações no C ++ 11 que fará com que algum código antigo pare de compilar: a introdução de explicit operator bool()na biblioteca padrão, substituindo instâncias antigas deoperator void*() . É verdade que o código que isso quebrará provavelmente é um código que não deveria ter sido válido em primeiro lugar, mas ainda assim é uma mudança de quebra: os programas que costumavam ser válidos não são mais.

Existem outras mudanças de última hora?


1
Removendo o significado da exportpalavra - chave? Vou pegar meu casaco.
21711 Steve

7
Você sabe, eu não chamaria isso de mudança de conversão para bool uma "mudança radical" ... mais como uma "mudança punitiva".
Xeo

4
Quando toda a papelada necessária para criar essa união está apenas esperando para ser carimbada, claro, por que não?
Dennis Zickefoose

3
@ Xeo: mystream.good()não é o mesmo que bool(mystream)? good()é verdadeiro se nenhum sinalizador estiver definido. bool(mystream)ainda é falso se apenas eofbitestiver definido. !mystream.fail()seria o equivalente correto.
R. Martinho Fernandes

2
Nota do moderador : " Por favor, mantenha os comentários no tópico com a pergunta ou resposta em mãos. Ao discutir uma pergunta ou resposta, a discussão deve ser apenas sobre isso, a pergunta ou resposta em questão. Debater, em geral, não é construtivo para o estouro de pilha. Antagonizar certamente não é. "
Tim Post

Respostas:


178

O FDIS possui uma seção para incompatibilidades, no apêndice C.2 "C ++ e ISO C ++ 2003".

Resumo, parafraseando o FDIS aqui, para torná-lo (melhor) adequado como uma resposta SO. Adicionei alguns exemplos para ilustrar as diferenças.

Existem algumas incompatibilidades relacionadas à biblioteca nas quais eu não conheço exatamente as implicações, então deixo essas para que outras pessoas elaborem.

Linguagem principal


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

Novas palavras-chave: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert e thread_local


Certos literais inteiros maiores que podem ser representados por long podem mudar de um tipo inteiro sem sinal para long long assinado.


O código C ++ 2003 válido que usa divisão inteira arredonda o resultado para 0 ou para o infinito negativo, enquanto C ++ 0x sempre arredonda o resultado para 0.

(reconhecidamente não é realmente um problema de compatibilidade para a maioria das pessoas).


O código C ++ 2003 válido que usa a palavra-chave autocomo um especificador de classe de armazenamento pode ser inválido no C ++ 0x.


Conversões limitadas causam incompatibilidades com o C ++ 03. Por exemplo, o código a seguir é válido no C ++ 2003, mas inválido neste padrão internacional, porque double to int é uma conversão restritiva:

int x[] = { 2.0 };

As funções-membro especiais declaradas implicitamente são definidas como excluídas quando a definição implícita tiver sido mal formada.

Um programa C ++ 2003 válido que usa uma dessas funções-membro especiais em um contexto em que a definição não é necessária (por exemplo, em uma expressão que não é potencialmente avaliada) fica mal formada.

Exemplo por mim:

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

Alguns truques de tamanho foram usados ​​por alguns SFINAE e precisam ser alterados agora :)


Os destruidores declarados pelo usuário têm uma especificação de exceção implícita.

Exemplo por mim:

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

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

Esse código chama terminateem C ++ 0x, mas não em C ++ 03. Porque a especificação de exceção implícita A::~Ano C ++ 0x é noexcept(true).


Uma declaração válida do C ++ 2003 contendo exportestá incorreta no C ++ 0x.


Uma expressão válida do C ++ 2003 contendo >seguida imediatamente por outra >agora pode ser tratada como o fechamento de dois modelos.

No C ++ 03, >>sempre seria o token do operador de turno.


Permite chamadas dependentes de funções com ligação interna.

Exemplo por mim:

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

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

int main() { g(0); }

No C ++ 03, isso chama f(long), mas no C ++ 0x, isso chama f(int). Deve-se observar que, tanto em C ++ 03 quanto em C ++ 0x, as seguintes chamadas f(B)(o contexto de instanciação ainda considera apenas declarações de ligação externa).

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

A melhor correspondência f(A)não é obtida, porque não possui ligação externa.


Alterações na biblioteca

O código C ++ 2003 válido que usa qualquer identificador adicionado à biblioteca padrão C ++ de C ++ 0x pode falhar ao compilar ou produzir resultados diferentes neste Padrão Internacional.


O código C ++ 2003 válido que #includescabeçalhos com nomes de novos cabeçalhos de biblioteca padrão C ++ 0x pode ser inválido nesta Norma.


O código C ++ 2003 válido que foi compilado esperando que a troca ocorra <algorithm>talvez precise incluir<utility>


O espaço para nome global posixagora está reservado para padronização.


Válido código C ++ 2003 que define override, final, carries_dependency, ou noreturncomo macros é inválido em C ++ 0x.


"Permite chamadas dependentes de funções com ligação interna." Você poderia, por favor, elaborar a diferença entre seus dois exemplos? Estou claramente sentindo falta de algo.
Dennis Zickefoose

@Dennis, a alteração foi introduzida por open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 . Embora eles não comentem o fato, o "contexto de instanciação" ainda consiste apenas em "o conjunto de declarações com ligação externa declaradas antes do ponto de instanciação da especialização de modelo na mesma unidade de tradução". Portanto, a alteração que eles fizeram afeta apenas a pesquisa no contexto de definição.
Johannes Schaub - litb 19/06/11

No meu primeiro exemplo, a função de ligação interna foi visível e encontrada no contexto de definição do modelo. No meu segundo exemplo, a função de ligação interna precisaria fazer parte do contexto de instanciação a ser encontrado. Mas como não é, não pode ser encontrado.
Johannes Schaub - litb 19/06

Aliás, acho que o único caso em que é seguro para um contexto de definição de modelo encontrar uma função com ligação interna é quando a especialização de modelo de função é instanciada explicitamente apenas instanciada em uma TU (onde o modelo é definido), e todas as outras TUs contam com essa instanciação explícita. Em todos os outros casos (em que as outras TUs instanciaram a especialização), você violaria o ODR fazendo com que a definição do modelo usasse uma função diferente (ligação interna) a cada vez.
Johannes Schaub - litb 19/06

Portanto, não sei por que eles mantiveram a restrição no contexto da instanciação - haveria apenas uma instanciação (explícita) e essa instanciação usaria funções de ligação internas encontradas no contexto de instanciação da TU instanciadora. Assim como faria no contexto da definição. Aliás, acho que se ainda o tivéssemos export, acho que os outros TUs não precisariam confiar na instanciação explícita, mas poderiam instanciar o modelo em si. Então , faria diferença se as funções de ligação interna são ou não visíveis no contexto da instanciação.
Johannes Schaub - litb 19/06/11

28

O significado da palavra-chave automática foi alterado.


9
Se você estiver usando a autopalavra - chave, algo está muito errado com seu código. Por que diabos você usaria isso?
Elazar Leibovich

Essa não é uma mudança radical . Todo uso válido de C ++ 03 autopermanece válido no C ++ 11.
Drew Dormann

11
@DrewDormann int main() { auto int i = 0; return i; }é C ++ 03 perfeitamente válido, mas um erro de sintaxe no C ++ 11. O único aviso que posso receber dos compiladores no modo C ++ 03 é um aviso sobre compatibilidade.

24

Quebrando a mudança?

Bem, para uma coisa, se você usou decltype, constexpr, nullptr, etc. como identificadores, então você pode estar em apuros ...


21

Algumas incompatibilidades principais que não são cobertas pela seção de incompatibilidades:


O C ++ 0x trata o nome da classe injetada como um modelo, se o nome for passado como argumento para um parâmetro do modelo e como um tipo se for passado para um parâmetro do tipo modelo.

O código C ++ 03 válido pode se comportar de maneira diferente se depender do nome da classe injetada para ser sempre um tipo nesses cenários. Código de exemplo retirado do meu 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();
}

No C ++ 03, o código chama o segundo nas gduas vezes.


O C ++ 0x torna alguns nomes que eram dependentes no C ++ 03 agora não-dependentes. E exige que a pesquisa de nome de nomes qualificados não dependentes que se refira aos membros do modelo de classe atual seja repetida na instanciação e exige a verificação de que esses nomes pesquisem da mesma maneira que no contexto de definição de modelo.

O código C ++ 03 válido que depende da regra de dominância agora pode não ser mais compilado devido a essa alteração.

Exemplo:

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

Esse código C ++ 03 válido que chama A<int>::fnão é válido em C ++ 0x, porque a pesquisa de nome ao instanciar será encontrada A<int>::fem oposição aB::f , causando um conflito com a pesquisa em definição.

Neste ponto, não está claro se isso é um defeito no FDIS. O comitê está ciente disso e avaliará a situação.


Uma declaração de uso em que a última parte é igual ao identificador na última parte do qualificador no nome qualificado que denota uma classe base, que usando a declaração agora nomeia o construtor, em vez de membros com esse nome.

Exemplo:

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

O código de exemplo acima é bem formado em C ++ 03, mas mal formado em C ++ 0x, pois A::Bainda é inacessível em main.


14

A falha na extração de fluxo é tratada de maneira diferente.

Exemplo

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

Alterar proposta

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

Referência padrão

[C++03: 22.2.2.1.2/11]: O resultado do processamento do estágio 2 pode ser um dos

  • Uma sequência de caracteres foi acumulada no estágio 2 que é convertida (de acordo com as regras de scanf) em um valor do tipo de val. Este valor é armazenado em vale ios_base::goodbité armazenado em err.
  • A sequência de caracteres acumulados no estágio 2 teria causado scanfuma falha na entrada. ios_base::failbitestá atribuído a err. [ed: Nada é armazenado val.]

[C++11: 22.4.2.1.2/3]: [..] O valor numérico a ser armazenado pode ser um dos seguintes:

  • zero, se a função de conversão falhar ao converter o campo inteiro . ios_base::failbitestá atribuído a err.
  • o valor representável mais positivo, se o campo representar um valor positivo muito grande para ser representado val. ios_base::failbitestá atribuído a err.
  • o valor representável mais negativo ou zero para um tipo inteiro não assinado, se o campo representar um valor negativo muito grande para ser representado val. ios_base::failbitestá atribuído a err.
  • o valor convertido, caso contrário.

O valor numérico resultante é armazenado em val.

Implementações

  • O GCC 4.8 gera corretamente para C ++ 11 :

    Falha na afirmação `x == -1 '

  • GCC 4.5-4.8 toda a saída para C ++ 03 da seguinte maneira, que parece ser um bug:

    Falha na afirmação `x == -1 '

  • O Visual C ++ 2008 Express gera corretamente para C ++ 03:

    Falha na asserção: x == 0

  • O Visual C ++ 2012 Express gera incorretamente para o C ++ 11, o que parece ser um problema de status de implementação:

    Falha na asserção: x == 0


13

Como a introdução de operadores de conversão explícita é uma mudança radical? A versão antiga ainda será tão "válida" quanto antes.

Sim, a mudança de operator void*() constpara explicit operator bool() constserá uma mudança ininterrupta, mas somente se for usada de uma maneira que esteja errada por si só. O código em conformidade não será quebrado.

Agora, outra mudança importante é a proibição de restringir conversões durante a inicialização agregada :

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

Edit : Apenas lembrete, std::identity<T>será removido em C ++ 0x (veja a nota). É uma estrutura de conveniência para tornar os tipos dependentes. Como a estrutura realmente não faz muito, isso deve corrigi-lo:

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

Se os objetos de biblioteca padrão tiverem adicionado conversões explícitas, as conversões implícitas existentes poderão parar de funcionar. Mas não consigo imaginar um cenário em que a conversão não seja válida e faça algo útil.
Dennis Zickefoose

A introdução é uma mudança radical, porque substituirá a existente operator void*.
R. Martinho Fernandes

@Dennis: Aaah, agora entendo o que @Martinho quis dizer. Mas isso só será uma mudança se as pessoas a usarem de forma diferente da pretendida.
Xeo

"mas apenas se for usado de uma maneira errada por si só" - bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }Não há nada realmente errado com isso no C ++ 03, mas tornou-se um erro no C ++ 11. (Nota: GCC 4.9 ainda tem operator void*() constaqui, é por isso que não aceita o código em C ++ 11 Modo.)

std::identity<T>não foi removido no C ++ 11, porque não fazia parte do C ++ 03. Existiu brevemente no rascunho para C ++ 11 e foi removido do rascunho antes da padronização.
Howard Hinnant


7

Tem havido muita discussão sobre movimentos implícitos quebrando a compatibilidade com versões anteriores

( uma página antiga com discussão relevante )

Se você ler os comentários, o retorno implícito da movimentação também será uma mudança de última hora.


O resultado dessas discussões é que ele foi removido em quase todos os casos. Há algum problema com o que resta?
Dennis Zickefoose

@ Dennis: Sim. Sua pergunta já foi feita, respondida e debatida até a morte nesta página de acompanhamento
Ben Voigt

Ahh, a página móvel não mostrou os comentários. De qualquer forma, esse é o link muito mais útil ... As peculiaridades históricas do processo de padronização não são tão relevantes (a menos que você esteja usando o MSVC, que acredito que use esse primeiro rascunho).
Dennis Zickefoose

@ Dennis: Eu acho que você está certo. Movido os links em torno de alguns na minha resposta.
amigos estão dizendo sobre ben

Infelizmente, o cpp-next.com não existe mais. Para referência futura, são páginas salvas pelo web.archive.org: movimento implícito, quebrando a compatibilidade com versões anteriores e uma página antiga com discussão relevante .
precisa saber é o seguinte

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

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03: válido.

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


2
@ Xeo: o código é válido em C ++ 03. É um parâmetro com tipo struct xe sem nome.
Ben Voigt

Eu estava esperando pegar alguém. Eu só queria que o @Xeo não tivesse sido tão rápido em excluir o comentário dele, pois não consegui lê-lo!
Lightness Races in Orbit

@ Xeo: sem procurar na gramática, tenho certeza que auto simplesmente não é uma palavra-chave válida. Se fosse, provavelmente funcionaria como o esperado, mas é provavelmente muito difícil de definir corretamente.
Dennis Zickefoose

Vamos apenas dizer que você me pegou. Ele literalmente ignorou a estrutura. :)
Xeo

@Tomalek: Xeo apontou, com razão, que o C ++ 03 não tem int implícito.
Ben Voigt

-4

Características da linguagem

  1. Inicialização geral e uniforme usando {}
  2. auto
  3. Prevenção de estreitamento
  4. constexpr
  5. Faixa baseada em loop
  6. nullptr
  7. classe enum
  8. static_assert
  9. std :: initializer_list
  10. Referências de valor (mover semântica)
  11. >>
  12. Lambdas
  13. Modelos variáveis
  14. Aliases de tipo e modelo
  15. Caracteres Unicode
  16. tipo longo longo inteiro
  17. alignas e alignof
  18. decltype
  19. Literais de cadeia bruta
  20. POD generalizado
  21. Sindicatos generalizados
  22. Classes locais como argumentos de modelo
  23. Sintaxe do tipo de retorno de sufixo
  24. [[carry_dependency]] e [[noreturn]]
  25. especificador noexcept
  26. operador noexcept.
  27. Recursos do C99:
    • tipos integrais estendidos
    • concatenação de cadeia estreita / larga
    • _ _ STDC_HOSTED _ _
    • _Pragma (X)
    • macros vararg e argumentos de macro vazios
  28. _ _ func _ _
  29. Namespaces embutidos
  30. Delegando Construtores
  31. Inicializadores de membros da classe
  32. padrão e excluir
  33. Operadores de conversão explícitos
  34. Literais definidos pelo usuário
  35. Modelos externos
  36. Argumentos de modelo padrão para modelos de função
  37. Herança de construtores
  38. substituição e final
  39. Regra SFINAE mais simples e mais geral
  40. Modelo de memória
  41. thread_local

Componentes da biblioteca padrão

  1. initializer_list para contêineres
  2. Mover semântica para contêineres
  3. forward_list
  4. Hash containers
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. Ponteiros de gerenciamento de recursos
    • unique_ptr
    • shared_ptr
    • weak_ptr
  6. Suporte de simultaneidade
    • fio
    • mutexes
    • fechaduras
    • variáveis ​​de condição
  7. Suporte de simultaneidade de nível superior
    • packaged_thread
    • futuro
    • promessa
    • assíncrono
  8. tuplas
  9. regex
  10. Números aleatórios
    • uniform_int_distribution
    • distribuição normal
    • random_engine
    • etc.
  11. Nomes de tipo inteiro, como int16_t, uint32_t e int_fast64_t
  12. matriz
  13. Copiando e repetindo exceções
  14. erro no sistema
  15. operações emplace () para contêineres
  16. funções constexpr
  17. Uso sistemático de funções noexcept
  18. funcionar e ligar
  19. Conversões de string para valor numérico
  20. Alocadores com escopo definido
  21. Traços de tipo
  22. Utilitários de tempo: duração e time_point
  23. Razão
  24. quick_exit
  25. Mais algoritmos, como move (), copy_if () e is_sorted ()
  26. Coleta de lixo ABI
  27. atômica

Recursos preteridos

  1. Geração do construtor de cópias e a atribuição de cópias para uma classe com um destruidor.
  2. Atribua uma string literal a um caractere *.
  3. Especificação de exceção C ++ 98
    • inexcepted_handler
    • set_unexpected
    • get_unexpected
    • inesperado
  4. Objetos de função e funções associadas
  5. auto_ptr
  6. registro
  7. ++ em um bool
  8. exportar
  9. Moldes em estilo C

3
Isso não responde à pergunta.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.