que - ¿Qué cambios de última hora se introducen en C++ 11?
programa c++ billetes y monedas (10)
Sé que al menos uno de los cambios en C ++ 11 hará que algunos códigos antiguos dejen de compilar: la introducción del explicit operator bool()
en la biblioteca estándar, que reemplaza las instancias antiguas de operator void*()
. Por supuesto, el código que se romperá es probablemente un código que no debería haber sido válido en primer lugar, pero aún así es un cambio importante: los programas que solían ser válidos ya no lo son.
¿Hay otros cambios de ruptura?
Características del lenguaje
- Inicialización uniforme y general utilizando {}
- auto
- Prevención del estrechamiento.
- constexpr
- Rango basado en bucle
- nullptr
- clase de enumeración
- static_assert
- std :: initializer_list
- Referencias de valor (movimiento semántico)
-
>>
- Lambdas
- Plantillas variables
- Alias de tipo y plantilla
- Personajes unicode
- long long integer type
- alignas y alignof
- decltype
- Literales de cuerda cruda
- POD generalizado
- Sindicatos generalizados
- Clases locales como argumentos de plantilla
- Sintaxis de tipo de retorno de sufijo
- [[carry_dependency]] y [[noreturn]]
- especificador noexcept
- Operador noexcept.
- Características del C99:
- tipos integrales extendidos
- concatenación de cuerda estrecha / ancha
- _ _ STDC_HOSTED _ _
- _Pragma (X)
- macros vararg y argumentos de macro vacíos
- _ _ func _ _
- Espacios de nombres en línea
- Constructores delegantes
- Inicializadores de miembros en clase
- predeterminado y eliminar
- Operadores de conversión explícita
- Literales definidos por el usuario
- Plantillas externas
- Argumentos de plantilla predeterminados para plantillas de función
- Heredando constructores
- anulación y final
- Regla SFINAE más simple y más general.
- Modelo de memoria
- thread_local
Componentes de la biblioteca estándar
- initializer_list para contenedores
- Mover la semántica para contenedores.
- forward_list
- Contenedores de hash
- unordered_map
- unordered_multimap
- unordered_set
- unordered_multiset
- Punteros de gestión de recursos
- unique_ptr
- shared_ptr
- débil_ptr
- Soporte de concurrencia
- hilo
- exclusión mutua
- cabellos
- variables de condición
- Soporte de concurrencia de alto nivel
- packaged_thread
- futuro
- promesa
- asíncrono
- tuplas
- expresiones regulares
- Números al azar
- uniform_int_distribution
- distribución normal
- random_engine
- etc.
- Nombres de tipo entero, como int16_t, uint32_t e int_fast64_t
- formación
- Copiar y volver a emitir excepciones.
- error del sistema
- emplace () operaciones para contenedores
- funciones constexpr
- Uso sistemático de las funciones noexcept.
- función y enlace
- Cadena a conversiones de valor numérico
- Asignadores de ámbito
- Tipo de rasgos
- Utilidades de tiempo: duración y time_point
- proporción
- quick_exit
- Más algoritmos, como move (), copy_if () y is_sorted ()
- Recolección de basura abi
- atomística
Características en desuso
- Generación del constructor de copia y la asignación de copia para una clase con un destructor.
- Asignar un literal de cadena a un char *.
- Especificación de la excepción C ++ 98
- Manejador sin excepción
- set_unexpected
- get_unexpected
- inesperado
- Objetos de función y funciones asociadas.
- auto_ptr
- registro
- ++ en un bool
- exportar
- Moldes de estilo C
Algunas incompatibilidades básicas que no están cubiertas por la sección de incompatibilidades:
C ++ 0x trata el nombre de la clase inyectada como una plantilla, si el nombre se pasa como un argumento a un parámetro de plantilla de plantilla, y como un tipo si se pasa a un parámetro de tipo de plantilla.
El código válido de C ++ 03 puede comportarse de manera diferente si confía en que el nombre de la clase inyectada sea siempre un tipo en estos escenarios. Código de ejemplo tomado de mi 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();
}
En C ++ 03, el código llama a la segunda g
ambas ocasiones.
C ++ 0x hace que algunos nombres que eran dependientes en C ++ 03 ahora no sean dependientes. Y requiere la búsqueda de nombres para los nombres calificados no dependientes que se refieren a los miembros de la plantilla de clase actual para que se repitan en la instanciación, y requiere la verificación de que estos nombres busquen de la misma manera que se hace en el contexto de definición de la plantilla.
El código válido de C ++ 03 que depende de la regla de dominancia ya no se puede compilar debido a este cambio.
Ejemplo:
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(); }
Este código de C ++ 03 válido que llama a A<int>::f
no es válido en C ++ 0x, porque la búsqueda de nombres al crear instancias encontrará A<int>::f
en lugar de B::f
, causando un conflicto con la búsqueda en definición.
En este punto, no está claro si eso es un defecto en el FDIS. El comité es consciente de esto y evaluará la situación.
Una declaración de uso donde la última parte es el mismo que el identificador en la última parte del calificador en el nombre calificado que denota una clase base, que utilizando la declaración ahora nombra al constructor, en lugar de miembros con ese nombre.
Ejemplo:
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; }
El código de ejemplo anterior está bien formado en C ++ 03, pero está mal formado en C ++ 0x, ya que A::B
todavía es inaccesible en main
.
El FDIS tiene una sección de incompatibilidades, en el apéndice C.2
"C ++ e ISO C ++ 2003".
Resumen, parafraseando el FDIS aquí, para hacerlo (mejor) adecuado como una respuesta SO. Agregué algunos ejemplos propios para ilustrar las diferencias.
Hay algunas incompatibilidades relacionadas con la biblioteca en las que no sé exactamente las implicaciones de, así que las dejo para que otros las desarrollen.
Lenguaje central
#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 .
Nuevas palabras clave: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert y thread_local
Ciertos literales enteros más grandes que los que se pueden representar por mucho tiempo podrían cambiar de un tipo entero sin signo a un signo largo y largo.
El código válido de C ++ 2003 que utiliza la división entera redondea el resultado hacia 0 o hacia el infinito negativo, mientras que C ++ 0x siempre redondea el resultado hacia 0.
(Es cierto que no es realmente un problema de compatibilidad para la mayoría de las personas).
El código válido de C ++ 2003 que usa la palabra clave
auto
como un especificador de clase de almacenamiento puede no ser válido en C ++ 0x.
Las reducciones de conversiones causan incompatibilidades con C ++ 03. Por ejemplo, el siguiente código es válido en C ++ 2003 pero no válido en esta Norma Internacional porque doble a int es una conversión restringida:
int x[] = { 2.0 };
Las funciones miembro especiales declaradas implícitamente se de fi nen como eliminadas cuando la definición implícita hubiera sido mal formada.
Un programa válido de C ++ 2003 que usa una de estas funciones miembro especiales en un contexto donde no se requiere la definición (por ejemplo, en una expresión que no es potencialmente evaluada) se vuelve mal formado.
Ejemplo por mi:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
Tal tamaño de trucos ha sido usado por algunos SFINAE, y necesita ser cambiado ahora :)
Los destructores declarados por el usuario tienen una especificación de excepción implícita.
Ejemplo por mi:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
Las llamadas de este código terminate
en C ++ 0x, pero no en C ++ 03. Debido a que la especificación de excepción implícita de A::~A
en C ++ 0x es noexcept(true)
.
Una declaración válida de C ++ 2003 que contiene la
export
está mal formada en C ++ 0x.
Una expresión válida de C ++ 2003 que contiene
>
seguida inmediatamente por otra>
puede tratarse ahora como cierre de dos plantillas.
En C ++ 03, >>
siempre sería el token de operador de cambio.
Permitir llamadas dependientes de funciones con enlace interno.
Ejemplo por mi:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
En C ++ 03, esto llama f(long)
, pero en C ++ 0x, esto llama f(int)
. Cabe señalar que tanto en C ++ 03 como en C ++ 0x, las siguientes llamadas f(B)
(el contexto de creación de instancias todavía solo considera declaraciones de vinculación externas).
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); }
No se toma la mejor concordancia f(A)
, porque no tiene enlace externo.
Cambios de biblioteca
El código válido de C ++ 2003 que usa cualquier identificador agregado a la biblioteca estándar de C ++ de C ++ 0x puede no compilar o producir resultados diferentes en esta Norma Internacional.
El código válido de C ++ 2003 que
#includes
encabezados con los nombres de los nuevos encabezados de biblioteca estándar de C ++ 0x puede no ser válido en esta Norma Internacional.
El código válido de C ++ 2003 que se ha compilado esperando que el swap esté en
<algorithm>
puede tener que incluir<utility>
El espacio de nombres global
posix
ahora está reservado para la estandarización.
El código válido de C ++ 2003 que define la
override
,final
,carries_dependency
onoreturn
como macros no es válido en C ++ 0x.
El significado de la palabra clave auto cambió.
Ha habido mucha discusión sobre el movimiento implícito que rompe la compatibilidad hacia atrás
( una página más antigua con discusión relevante )
Si lees en los comentarios, el retorno de movimiento implícito también es un cambio importante.
Hay numerosos cambios en la biblioteca de contenedores que permiten un código más eficiente, pero rompen silenciosamente la compatibilidad hacia atrás para algunos casos de esquina.
Considere, por ejemplo, std::vector
, construcción predeterminada, C ++ 0x y cambios de ruptura .
La falla de extracción de la corriente se trata de manera diferente
Ejemplo
#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
}
Propuesta de cambio
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
Referencia estándar
[C++03: 22.2.2.1.2/11]:
El resultado del procesamiento de la etapa 2 puede ser uno de
- Una secuencia de caracteres se ha acumulado en la etapa 2 que se convierte (de acuerdo con las reglas de
scanf
) a un valor del tipo deval
. Este valor se almacena enval
yios_base::goodbit
se almacena enerr
.- La secuencia de caracteres acumulados en la etapa 2 habría causado que
scanf
informara un error de entrada.ios_base::failbit
se asigna aerr
. [ed: Nada se almacena enval
.]
[C++11: 22.4.2.1.2/3]:
[..] El valor numérico que se almacenará puede ser uno de los siguientes:
- cero, si la función de conversión no logra convertir todo el campo .
ios_base::failbit
se asigna aerr
.- el valor representable más positivo, si el campo representa un valor positivo demasiado grande para ser representado en
val
.ios_base::failbit
se asigna aerr
.- el valor representable más negativo o cero para un tipo entero sin signo, si el campo representa un valor negativo demasiado grande para ser representado en
val
.ios_base::failbit
se asigna aerr
.- el valor convertido, de lo contrario.
El valor numérico resultante se almacena en
val
.
Implementaciones
GCC 4.8 sale correctamente para C ++ 11 :
Afirmación `x == -1 ''falló
GCC 4.5-4.8 todos los resultados para C ++ 03 son los siguientes, que parecen ser un error:
Afirmación `x == -1 ''falló
Visual C ++ 2008 Express genera correctamente para C ++ 03:
Afirmación fallida: x == 0
Visual C ++ 2012 Express produce resultados incorrectos para C ++ 11, lo que parece ser un problema de estado de implementación:
Afirmación fallida: x == 0
Rompiendo el cambio?
Bueno, por un lado, si usó decltype
, constexpr
, nullptr
, etc. como identificadores, entonces podría estar en problemas ...
¿Cómo es la introducción de operadores de conversión explícitos un cambio de ruptura? La versión anterior seguirá siendo tan "válida" como antes.
Sí, el cambio del operator void*() const
al explicit operator bool() const
será un cambio importante, pero solo si se usa de forma incorrecta dentro y fuera de sí mismo. El código de conformidad no se romperá.
Ahora, otro cambio importante es la prohibición de reducir las conversiones durante la inicialización agregada :
int a[] = { 1.0 }; // error
Edición : solo recordatorio, std::identity<T>
se eliminará en C ++ 0x (vea la nota). Es una estructura de conveniencia para hacer tipos dependientes. Dado que la estructura realmente no hace mucho, esto debería arreglarlo:
template<class T>
struct identity{
typedef T type;
};
struct x {
x(int) {}
};
void f(auto x = 3) { }
int main() {
f();
}
C ++ 03: válido.
C ++ 0x: error: parameter declared ''auto''