Qual é a ordem de destruição dos argumentos da function?

Se alguma function f com parâmetros p_1 , …, p_n dos tipos T_1 , …, T_n respectivamente é chamada com argumentos a_1 , …, a_n e seu corpo lançam uma exceção, terminam ou retornam, em que ordem são os argumentos destruídos e por quê? Por favor, forneça uma referência ao padrão, se possível.

EDIT: Eu realmente queria perguntar sobre a function “parâmetros”, mas como TC e Columbo conseguiu limpar a minha confusão, eu estou deixando esta questão ser sobre os argumentos e fez uma nova pergunta em separado sobre os parâmetros . Veja os comentários sobre esta questão para a distinção.

A ordem na qual os argumentos para uma function são avaliados não é especificada pelo padrão. Do Padrão C ++ 11 ( rascunho online ):

5.2.2 Chamada de function

8 [ Nota: As avaliações da expressão postfix e das expressões de argumentos são todas não sequenciadas em relação umas às outras. Todos os efeitos colaterais das avaliações de expressões de argumentos são sequenciados antes que a function seja inserida (veja 1.9). – end note ]

Portanto, cabe a uma implementação decidir em que ordem avaliar os argumentos para uma function. Isso, por sua vez, implica que a ordem de construção dos argumentos também é dependente da implementação.

Uma implementação sensata destruiria os objects na ordem inversa de sua construção.

Eu não consegui encontrar a resposta no padrão, mas eu pude testar isso em 3 compiladores compatíveis com C ++ mais populares. A resposta de R Sahu explica basicamente que é uma implementação definida.

§5.2.2 / 8 : As avaliações da expressão postfix e dos argumentos são todas sem seqüência relativas uma à outra. Todos os efeitos colaterais das avaliações de argumentos são sequenciados antes que a function seja inserida.

Compilador Visual Studio C ++ (Windows) e gcc (Debian)
Os argumentos são construídos em ordem inversa à sua declaração e destruídos em ordem inversa (assim destruídos por ordem de delação):

2
1
-1
-2

Clang (FreeBSD)
Os argumentos são construídos em ordem de sua declaração e destruídos em ordem inversa:

1
2
-2
-1

Todos os compiladores foram instruídos a tratar o código-fonte como C ++ 11 e usei o seguinte trecho para demonstrar a situação:

 struct A { A(int) { std::cout << "1" << std::endl; } ~A() { std::cout << "-1" << std::endl; } }; struct B { B(double) { std::cout << "2" << std::endl; } ~B() { std::cout << "-2" << std::endl; } }; void f(A, B) { } int main() { f(4, 5.); } 

Em §5.2.2 [4] N3337 é bastante explícito sobre o que acontece ( rascunho online ):

Durante a boot de um parâmetro, uma implementação pode evitar a construção de extra-temporárias combinando as conversões no argumento associado e / ou a construção de provisórios com a boot do parâmetro (ver 12.2). O tempo de vida de um parâmetro termina quando a function na qual ele está definido retorna.

Então, por exemplo, em

 f(g(h())); 

o valor de retorno da chamada h() é um temporário que será destruído no final da expressão completa. No entanto, o compilador tem permissão para evitar este temporário e inicializar diretamente com seu valor o parâmetro de g() . Nesse caso, o valor de retorno será destruído quando g() retornar (isto é, ANTES de chamar f() ).

Se eu entendi corretamente o que é declarado no padrão, não é permitido ter o valor retornado de h() para sobreviver até o final da expressão completa, a menos que uma cópia seja feita (o parâmetro) e essa cópia seja destruída uma vez g() retorna.

Os dois cenários são:

  1. h valor de retorno é usado para inicializar diretamente o parâmetro g . Este object é destruído quando g retorna e antes de chamar f .
  2. h valor de retorno é temporário. Uma cópia é feita para inicializar o parâmetro g e é destruída quando g retorna. O temporário original é destruído no final da expressão completa.

Não sei se implementações estão seguindo as regras sobre isso.

    Intereting Posts