¡C ++ 20 aprobado! Qué esperar y qué preparar para los desarrolladores en C ++ 23

El otro día en Praga, tuvo lugar una reunión del comité internacional de normalización C ++. Y-y-y-y ... ¡



C ++ 20 está listo! Queda por poner un sello de ISO, pero este es un paso puramente formal con el que no debería haber problemas.

¡Felicitaciones a todos por este maravilloso evento! Conceptos, Coroutines, Módulos, Rangos, std :: format, constexpr new y constexpr Algoritmos + vector + string, datetime, jthread, span, bit_cast y muchas otras innovaciones pequeñas y grandes.

Lo que lograron agregar y arreglar en el último momento, lo que propusieron romper y lo que todos quieren ver en C ++ 23, sobre todo esto bajo el corte.

Trucos de C a C ++ 20


Recientemente, ha habido una tradición de asustar a los desarrolladores novatos con comportamiento indefinido (UB) en C ++. ¡Es hora de cambiarlo!

Aquí, por ejemplo, dicho código es absolutamente válido para C:

struct X { int a, b; };

X *make_x() {
  X *p = (X*)malloc(sizeof(struct X));
  p->a = 1;
  p->b = 2;
  return p;
}

Pero en C ++ hubo grandes problemas con él. C opera con bytes y C ++ funciona con objetos. Pero el objeto tiene una vida útil, y antes de C ++ 20, el comienzo de la vida del objeto se consideraba desde la llamada new.

El comité está seriamente preocupado por el trabajo de bajo nivel con bytes y estructuras simples. Adoptaron mejoras que dicen que un cierto conjunto de funciones (memcpy, memmove, malloc, lined_alloc, calloc, realloc, bit_cast) comienza la vida útil del objeto. Ahora se garantiza que la mayoría de los trucos C de bajo nivel funcionarán en C ++.

bool se ha vuelto más confiable en C ++ 20


Adivina cuál es el error:

template <typename T, size_t N>
auto count_unique(const std::array<T, N>& v) {
    return std::unordered_set<T>{v.begin(), v.end()}.size();
}

Responder
T bool v.begin() v.end() (, libc++ libstdc++) — count_unique 1.

- , std::unordered_set<bool>{v.begin(), v.end()} bool std::unordered_set<bool>{true, true}.

Las transformaciones en bool ahora se consideran reducciones de transformaciones. Esto nos permitió encontrar problemas en muchas bases de código (más ejemplos en la oración P1957 en sí ).

Conceptos de C ++ 20 más rápidos


Hasta hace poco, podría escribir un concepto como este:

template <class T>
concept Reservable = requires(T v) {
    v.reserve(int{});
};

Y se sorprenderá de que arroje resultados diferentes:

struct Test;

static_assert(!Reservable<Test>);

struct Test {
    void reserve(int);
};

static_assert(Reservable<Test>);

La última vez, enviamos un comentario desde el país: "Hacer que sea imposible usar conceptos de tipo incompleto, porque de lo contrario se obtienen múltiples violaciones de ODR". Nuestro comentario fue rechazado, pero ahora obtuvimos parcialmente el resultado deseado con la propuesta P2104.

Como beneficio adicional, obtenemos una compilación más rápida, ya que los compiladores ahora tienen derecho a almacenar en caché los resultados de aplicar conceptos a los tipos.

Ediciones menores en C ++ 20


  • Los rangos obtuvieron el método ssize.
  • El enlace interno de las entidades ya no es visible cuando se crean instancias de entidades de enlace del módulo (el compilador le dirá qué está mal en la etapa de compilación).
  • Cambiamos las reglas de los módulos para que sea más fácil para cualquier herramienta trabajar con ellos.

¿Y rompamos todo en C ++ 23 o C ++ 26?


El debate prolongado ha generado una propuesta para una interfaz binaria de aplicación (ABI, no confunda con la API). Se plantearon preguntas interesantes:

1. Podemos cambiar completamente ABI en C ++ 23 y obtener una ganancia de rendimiento del 5-10%.


Además, todas las bibliotecas antiguas de C ++ tendrán que ser reconstruidas; no podrán vincularse a bibliotecas con el nuevo ABI. No puede usar bibliotecas creadas por versiones anteriores de C ++ en un proyecto C ++ 23.

Bueno, por supuesto, siempre habrá un viejo software comercial que nadie volverá a montar, pero que arrastrará su biblioteca estándar (sí, ¡videojuegos, estoy hablando de ti!).

Con un ligero margen de voto, ABI decidió no romper en C ++ 23.

2. Démosles a los usuarios una garantía de que intentaremos no romper / cambiar el ABI.


Y luego decidieron no dar una garantía. Diferentes proveedores tienen diferentes planes para sus plataformas, y a veces pueden permitirse el lujo de romper la ABI, a menudo sin dañar a los usuarios.

¿Y agreguemos a todas partes sin excepción?


Históricamente, en las funciones estándar con condiciones previas no se marcan como no, excepto si nunca arrojan excepciones. Aquí, por ejemplo, operador -> have std :: opcional:

constexpr const T* operator->() const;
constexpr T* operator->();
    Requires: *this contains a value.
    Returns: val.
    Throws: Nothing.

No arroja nada, pero en lugar de no decir nada, dice en palabras que "Lanza: Nada", porque hay una condición previa "* esto contiene un valor".

Los usuarios sin excepción serán más claros. ¡Una buena idea en P1656 !



¡No!

Existe todo un subgrupo SG21: Contratos, que presenta un mecanismo común para verificar los contratos (pre y post condiciones). Los manejadores de contratos pueden lanzar una excepción, si se lanza una excepción desde la función noexcept, será std :: terminate y la aplicación se bloqueará. Si inserta una muleta especial que para las excepciones de los contratos puede salir volando de una función noexcept ... entonces todo se rompe de todos modos, los rasgos de tipo se guían por la presencia de noexcept, y comienzan a mentirle, una función marcada con noexcept con una condición previa arrojará una excepción.

Pero este no es el mayor problema. Hay tenedores de bibliotecas estándar, que ya ahora en algunos casos insertan explícitamente verificaciones de precondición. Por ejemplo, ¿tiene un proyecto crítico, cuya disponibilidad debe maximizarse? Utiliza una bifurcación similar, y si alguien repentinamente llama a std :: vector :: back () para un vector vacío, se produce una excepción, que se procesa más arriba en el código y comienza a utilizarse la reserva. Con ediciones de P1656, dicha biblioteca ya no puede considerarse estándar.

¡Y estos no son todos los problemas! .. No solo el no-excepción adicional para la biblioteca estándar traerá ningún efecto positivo en forma de una disminución en el tamaño de los archivos binarios o más rendimiento, no solo el cambio romperá el código de al menos dos compañías, no solo destruirá una de las formas uso de contratos ... así también la propuesta fue aprobada en dos subgrupos.

Méritos de RG21


Como siempre, trabajamos en varios subgrupos, compartimos experiencias de implementación, presentamos propuestas, cuyos autores no pudieron asistir.

Una de las ideas sobresalientes que tuvimos la suerte de presentar fue la idea de Anton Zhilin P2025 Elisión de copia garantizada para objetos de devolución con nombre . Su implementación permitirá crear funciones de fábrica para objetos sin copiar y mover constructores. De hecho, este es un movimiento destructivo, que ha existido en secreto en el estándar desde mediados de los 90 y estaba específicamente prohibido por las reglas del idioma individual.

Arrastramos con éxito la idea a través de las instancias EWG-I y EWG gracias a la excelente elaboración de la idea por el propio autor. La etapa de CWG permaneció, y después de un par de reuniones hay todas las posibilidades de ver las palabras necesarias en el estándar y las primeras implementaciones en los compiladores.

Además de esta idea, arrastramos la idea de P1990R0: Agregar operador [] a std :: initializer_list a través de LEWG-I, obtuve una respuesta útil sobre P1944R0: constexpr <cstring> y <cwchar> . Ambas ideas de Daniil Goncharov tienen todas las posibilidades de estar en C ++ 23.

En el campo de std :: hash, nos esperaba un error inesperado. La discusión de p1406r1: Agregar más especializaciones std :: hash de repente se convirtió en una discusión de casos límite degenerados y las posibilidades de C ++ 2 * distante. Como resultado, el comité decidió no cambiar nada.

Con SG6 y Numbers no crecieron juntos. Las discusiones principales de SG6 se cruzaron con las discusiones de ABI, por lo que el quórum en SG6 no se acumuló. Debido a esto p1889: C ++ Numerics Work In Progress , P2010: eliminar operadores iostream de P1889 yP1890: No se discutieron los problemas de trabajo en progreso de C ++ Numerics .

C ++ 23 planes


Desde el comienzo del desarrollo de C ++ 20, el comité comenzó a actuar de acuerdo con el plan. Es decir, identificar varias ideas importantes para el próximo estándar, después de lo cual en todas las reuniones posteriores no considerar propuestas sobre otros temas, si no todos se han discutido sobre el principal.

Para C ++ 23, dicho plan se acaba de aprobar en Praga. Las principales prioridades de C ++ 23:

  1. Soporte de corutina en la biblioteca estándar.
  2. Convertir biblioteca estándar a módulos
  3. Ejecutores
  4. Redes

En el primer párrafo, todos serán guiados por la biblioteca CppCoro . Entonces, si ya desea usar corutinas C ++ 20, debe comenzar usando esta biblioteca.

Con los módulos, el segundo punto, solo necesita sentarse y hacerlo, no se esperan dificultades especiales.

Pero los ejecutores es un problema. Su diseño no es obvio, no todos los casos de usuarios están cubiertos, en su forma actual no fueron utilizados por nadie, y el diseño aún no está aprobado.

El comité también acordó priorizar las propuestas en las siguientes áreas:

  • Reflexión
  • La coincidencia de patrones
  • Contratos

En lugar de totales


C ++ 20 está listo, ¡es hora de trabajar en C ++ 23! La próxima reunión del Comité será en el verano, así que si tienes una idea decente del nuevo estándar, compártelos en stdcpp.ru y en Program de chat de Telegram .

Bueno, todos los que quieran chatear con representantes del comité en vivo - miren las reuniones y conferencias de C ++ *:


* Life hack: no tienes que pagar un boleto de conferencia si eres un orador.

All Articles