Ordem de avaliação em parâmetros de função C ++

89

Se tivermos três funções (foo, bar e baz) que são compostas assim ...

foo(bar(), baz())

Existe alguma garantia pelo padrão C ++ de que a barra será avaliada antes do baz?

Clark Gaebel
fonte

Respostas:

101

Não, não existe essa garantia. Não é especificado de acordo com o padrão C ++.

Bjarne Stroustrup também diz isso explicitamente na seção 6.2.2 "The C ++ Programming Language" 3ª edição, com alguns argumentos:

Um código melhor pode ser gerado na ausência de restrições na ordem de avaliação da expressão

Embora tecnicamente isso se refira a uma parte anterior da mesma seção que diz que a ordem de avaliação das partes de uma expressão também não é especificada, ou seja,

int x = f(2) + g(3);   // unspecified whether f() or g() is called first
Eli Bendersky
fonte
Posso aceitar essa resposta em 8 minutos ... Acho que vou demorar um pouco!
Clark Gaebel
4
Sim, mas um código melhor poderia ser ESCRITO (= mais limpo) se a ordem de avaliação da expressão fosse ESTRITA, o que geralmente é muito mais importante do que a geração de código. Veja este exemplo: stackoverflow.com/questions/43612592/… Então, Stroustrup.
Bill Kotsias,
1
Se o pedido for importante, você pode fazer o sequenciamento sozinho. Fazer o contrário sempre incorreria em um custo por algo que nem sempre (raramente?) Importa. Acho que a política de não pagar pelo que você não usa é a única coisa com a qual a maioria dos programadores de C ++ concorda.
tweej
3
Não deveria ser "comportamento não especificado" em vez de "indefinido"?
GoodDeeds
1
@ChrisDodd rejeitar uma resposta aceita devido ao uso da palavra "indefinido" vs. "não especificado" parece um pedantismo malicioso para mim ... Eu não disse que isso é "comportamento indefinido" e, de outra forma, "indefinido" e "não especificado" parecem sinônimo? Em qualquer caso, propor uma edição para a resposta teria sido uma maneira mais produtiva de discutir isso
Eli Bendersky
20

Não há ordem especificada para bar () e baz () - a única coisa que o padrão diz é que ambos serão avaliados antes de foo () ser chamado. Do padrão C ++, seção 5.2.2 / 8:

A ordem de avaliação dos argumentos não é especificada.


fonte
4
O fato de que eles são avaliados antes de foo () é um pouco reconfortante, pelo menos.
Bill Kotsias,
1
@BillKotsias O padrão também diz que as chamadas de função não podem se sobrepor (ou seja, uma implementação não pode executar a linha 1 de bar, a seguir a linha 1 de baz, a linha 2 de baretc.), o que também é bom. :-)
melpomene
20

De [5.2.2] chamada de função,

A ordem de avaliação dos argumentos não é especificada. Todos os efeitos colaterais das avaliações de expressão de argumento têm efeito antes que a função seja inserida.

Portanto, não há garantia de que bar()será executado antes baz(), apenas que bar()e baz()será chamado antes foo.

Observe também em [5] Expressões que:

exceto onde indicado [por exemplo, regras especiais para &&e ||], a ordem de avaliação dos operandos de operadores individuais e subexpressões de expressões individuais, e a ordem em que os efeitos colaterais ocorrem, não é especificada.

então, mesmo que você perguntasse se bar()será executado antes baz()em foo(bar() + baz()), a ordem ainda não foi especificada.

Daniel Trebbien
fonte
4
Um exemplo de uma "nota especial" de [5.14] Operador lógico AND: "Ao contrário &, &&garante a avaliação da esquerda para a direita: o segundo operando não é avaliado se o primeiro operando for false."
Daniel Trebbien
2

Em C ++ 11, o texto relevante pode ser encontrado em 8.3.6 Argumentos padrão / 9 (Ênfase minha)

Os argumentos padrão são avaliados sempre que a função é chamada. A ordem de avaliação dos argumentos da função não é especificada . Conseqüentemente, os parâmetros de uma função não devem ser usados ​​em um argumento padrão, mesmo se não forem avaliados.

O mesmo palavreado também é usado pelo padrão C ++ 14 e pode ser encontrado na mesma seção .

R Sahu
fonte
0

Como outros já apontaram, a norma não fornece nenhuma orientação sobre a ordem de avaliação para este cenário específico. Essa ordem de avaliação é então deixada para o compilador, e o compilador pode ter uma garantia.

É importante lembrar que o padrão C ++ é realmente uma linguagem para instruir um compilador na construção de código de montagem / máquina. O padrão é apenas uma parte da equação. Onde o padrão é ambíguo ou é especificamente definido pela implementação, você deve recorrer ao compilador e entender como ele traduz as instruções C ++ em verdadeira linguagem de máquina.

Portanto, se a ordem de avaliação for um requisito, ou pelo menos importante, e ser compatível com compilador cruzado não é um requisito, investigue como seu compilador acabará por juntar isso, sua resposta pode estar aí. Observe que o compilador pode mudar sua metodologia no futuro

Programador Erudito
fonte