make_tuple - tuple c++ example
C++ std:: tuple orden de destrucción (3)
¿Hay alguna regla que indique en qué orden se destruyen los miembros de una std :: tuple?
Por ejemplo, si Function1
devuelve std::tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>>
a Function2
, entonces puedo estar seguro de que (cuando queda el alcance de Function2
) la instancia de ClassB
refirió ¿Por el segundo miembro se destruye antes de la instancia de ClassA
referida por el primer miembro?
std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > Function1()
{
std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > garbage;
get<0>(garbage).reset( /* ... */ );
get<1>(garbage).reset( /* ... */ );
return garbage;
}
void Function2()
{
auto to_be_destroyed = Function1();
// ... do something else
// to_be_destroyed leaves scope
// Is the instance of ClassB destroyed before the instance of ClassA?
}
Con Clang 3.4 obtengo el mismo orden de destrucción para std::pair
y 2 elementos std::tuple
y con g ++ 5.3 obtengo un orden opuesto que podría deberse principalmente a la implementación recursiva de std::tuple
en libstd ++.
Entonces, básicamente se reduce a lo que dije en el comentario, es implementación definida.
Del informe BUG :
Comentario de Martin Sebor
Como el diseño de los miembros std :: pair está completamente especificado, también lo es el orden de inicialización y destrucción. La salida del caso de prueba refleja este orden.
El orden de inicialización (y destrucción) de los subobjetos std: stuple está menos claramente especificado. Al menos no es inmediatamente obvio por mi lectura de la especificación si se requiere alguna orden en particular.
El motivo por el que la salida de std :: tuple con libstdc ++ es inversa a std :: pair se debe a que la implementación, que depende de la herencia recursiva, almacena y construye elementos de tupla en el orden inverso: es decir, la clase base, que almacena el último elemento, se almacena y construye primero, seguido de cada clase derivada (cada una de las cuales almacena el último elemento - Nth).
La cita del estándar [sección 20.4.1] que el reportero de errores está citando a
1 Esta subcláusula describe la biblioteca de tuplas que proporciona un tipo de tupla como la tupla de plantilla de clases que se puede instanciar con cualquier cantidad de argumentos. Cada argumento de plantilla especifica el tipo de un elemento en la tupla. En consecuencia, las tuplas son colecciones heterogéneas de valores fijos. Una instanciación de tupla con dos argumentos es similar a una instanciación de un par con los mismos dos argumentos . Ver 20.3.
El argumento en contra de esto hecho en el error vinculado es:
Ser descrito como similar no implica que sean idénticos en cada detalle. std :: pair y std :: tuple son clases distintas con diferentes requisitos en cada una. Si considera que se requiere que se comporte de forma idéntica a este respecto (es decir, que sus subobjetos estén definidos en el mismo orden), debe señalar la redacción específica que lo garantiza.
El estándar no especifica el orden de destrucción para std::tuple
. El hecho de que §20.4.1 / p1 especifica que:
Una instanciación de tupla con dos argumentos es similar a una instanciación de un par con los mismos dos argumentos.
Similar aquí no se interpreta como idéntico y, en consecuencia, no está implícito que std::tuple
debe tener una orden de destrucción inversa de sus argumentos.
Dada la naturaleza recursiva de std::tuple
más probable es que el orden de destrucción esté en orden con el orden de sus argumentos.
También baso mis suposiciones en un informe de error para GCC BUG 66699, donde en el debate mis suposiciones anteriores están justificadas.
Dicho esto, el orden de destrucción para std::tuple
no está especificado.
Voy a ofrecer una lección de vida que he aprendido, en lugar de una respuesta directa, en respuesta a su pregunta:
Si puede formular, para múltiples alternativas, un argumento razonable sobre por qué esa alternativa debe ser la exigida por el estándar, entonces no debe suponer que ninguna de ellas sea obligatoria (incluso si una de ellas lo es).
En el contexto de las tuplas, por favor, sean amables con las personas que mantienen su código y no permitan que el orden de destrucción de los elementos de tupla potencialmente altere la destrucción de otros elementos. Eso es simplemente malo ... imagine al desventurado programador que tendrá que depurar esta cosa. De hecho, esa pobre alma podría ser tú misma en unos pocos años, cuando ya te hayas olvidado de tu astuto truco de la parte de atrás del día.
Si absolutamente debe confiar en el orden de destrucción, tal vez debería usar una clase adecuada con los elementos de la tupla como sus miembros de datos (para los que podría escribir un destructor, dejando en claro lo que debe suceder en qué orden) o algún otro arreglo que facilita un control más explícito de la destrucción.