c++ - El destructor no trivial hace que la clase no sea trivialmente construible
(1)
Este problema se trata en el número 2116 de LWG: std :: swap noexcept (what?) , Podemos ver esto en la sección de referencias de cpp para std::is_trivially_default_constructible :
En muchas implementaciones, is_nothrow_default_constructible también verifica si el destructor lanza porque es efectivamente noexept (T ()): error GCC 51452 LWG número 2116
que engañosamente solo se refiere a is_nothrow_default_constructible
pero si leemos el tema en detalle, vemos que también se aplica aquí.
Quizás sea más fácil si seguimos el informe de error de gcc: [DR 2116] has_nothrow _. * Errores del constructor al que se hace referencia primero, que dice:
Los rasgos que detectan la constructibilidad de nothrow son defectuosos porque están influenciados por si el objeto tiene un dtor de nothrow; la destrucción se invoca al final de la evaluación de la expresión completa en el operador noexcept (...). Todos usan el patrón de construcción de un noexcept temporal en el interior, mientras que deberían usar la colocación nueva.
esto dice explícitamente lo que solo se alude realmente en el problema de LWG que finalmente dice:
is_nothrow_constructible se define en términos de is_constructible, que se define observando una variable hipotética y preguntando si se sabe que la definición de la variable no genera excepciones. El problema afirma que esto también examina el destructor del tipo, dado el contexto, y por lo tanto devolverá falso si el destructor puede potencialmente lanzar . Al menos una implementación (la de Howard) devuelve falso si el constructor es noexcept (verdadero) y el destructor es noexcept (falso). Así que esa no es una interpretación tensa. El problema es que se defina esto en términos de ubicación nueva, en lugar de en términos de un objeto temporal, para que quede más claro que is_nothrow_constructible observa el estado de excepción de solo el constructor, y no el destructor.
que también afecta a std::is_trivially_default_constructible
que se basa en std::is_trivially_constructible que hace lo mismo que is_constructible
pero tiene la restricción adicional de que:
pero la definición de la variable no llama a ninguna operación que no sea trivial
Considere el siguiente código:
#include <type_traits>
struct T {};
static_assert(std::is_trivially_destructible< T >{});
static_assert(std::is_trivially_default_constructible< T >{});
struct N { ~N() { ; } };
static_assert(!std::is_trivially_destructible< N >{});
static_assert(!std::is_trivially_default_constructible< N >{});
Se compila bien usando clang 3.7.0
: ejemplo en vivo . Pero resumiendo el Estándar :
El constructor predeterminado para la clase T es trivial (es decir, no realiza ninguna acción) si todo lo siguiente es verdadero:
- El constructor no es proporcionado por el usuario (es decir, está definido de forma implícita o predeterminado)
- T no tiene funciones miembro virtuales
- T no tiene clases de base virtual
- T no tiene miembros no estáticos con inicializadores predeterminados. (desde C ++ 11)
- Cada base directa de T tiene un constructor por defecto trivial
- Cada miembro no estático de tipo de clase tiene un constructor predeterminado trivial
Como puedo ver, no hay dependencia de la trivialidad del destructor.
Me perdí algo? ¿Es clang
bug?
ADICIONAL
Encontré una solución alternativa: es static_assert(__has_trivial_constructor( N ));
Tipo de rasgo incorporado. Hay soporte en clang
, gcc
y MSVC
.
Para la familia is_noexcept_constructible
de rasgos de tipo, también hay una solución alternativa .