É possível alterar o objeto temporário e passá-lo como argumento?
-
21-09-2019 - |
Pergunta
É possível alterar o objeto temporário e passá-lo como argumento?
struct Foo {
Foo& ref() { return *this; }
Foo& operator--() { /*do something*/; return *this; }
// another members
};
Foo getfoo() { return Foo(); } // return Foo() for example or something else
void func_val(Foo x) {}
void func_ref(const Foo & x) {}
int main() {
func_val(--getfoo()); // #1 OK?
func_ref(getfoo()); // #2 OK?
func_ref(getfoo().ref()); // #3 OK?
// the following line is a real example
// using --vector.end() instead of --getfoo()
func_ref(--getfoo()); // #4 OK?
const Foo & xref = --getfoo(); // Does const extend the lifetime ?
func_ref(xref); // #5 OK?
func_val(xref); // #6 OK?
}
Sabe-se que atribuir um objeto temporário à referência const prolonga a vida útil desse objeto temporário.E quanto às linhas 4 e 5 do meu código?É verdade que a referência x é sempre válida na função func_ref?Acontece que o operador-- retorna alguma referência e o compilador não vê nenhuma relação entre essa referência e o temporário que criamos.
Solução
func_val(--getfoo()); // #1 OK?
Sim, ok.O operator--
é uma função-membro, que é chamada e que retorna a si mesma (e lvalue referindo-se a si mesmo).O objeto é então copiado para o parâmetro de func_val
.Observe que a otimização do valor de retorno não pode ser aplicada, uma vez que o temporário criado por getfoo()
estava anteriormente vinculado a uma referência.
func_ref(getfoo()); // #2 OK?
Sim, ok.A chamada getfoo()
retorna um temporário que está vinculado à referência const.Um construtor de cópia é necessário, mas a chamada dele pode ser otimizada pela implementação.O temporário persiste até o final da expressão completa que contém a chamada para func_ref
(toda a declaração da expressão aqui).
func_ref(getfoo().ref());
Sim, ok.Nenhum construtor de cópia é necessário, pois vinculamos a referência const não a um temporário, mas ao lvalue que representa o próprio objeto.
// the following line is a real example
// using --vector.end() instead of --getfoo()
Isso não é necessário para funcionar.Pense em uma situação em que vector.end()
retorna um T*
(permitido).Você não tem permissão para modificar valores de tipo que não seja de classe; portanto, nesse caso, isso seria mal formado.
func_ref(--getfoo());
Sim, ok.O argumento é avaliado como em #1
, mas o lvalue resultante é passado diretamente e a referência const está vinculada a ele.Neste sentido é igual a #3
(exceto para o efeito colateral de diminuição).
const Foo & xref = --getfoo();
A redação padrão não é totalmente clara.Certamente pretende apenas prolongar a vida útil de objetos ainda não vinculados a uma referência.Mas no nosso caso, --getfoo()
produz um lvalue referente a um objeto temporário que foi previamente vinculado a uma referência.Pode valer a pena enviar um relatório de defeito ao comitê (também posso ter perdido o texto que exige que o objeto temporário ainda não esteja vinculado a uma referência).
Em qualquer caso, o comportamento pretendido é destruir o temporário que resulta da getfoo()
no final da inicialização xref
, então xref
se tornará uma referência pendente.
Acontece que o operador-- retorna alguma referência e o compilador não vê nenhuma relação entre essa referência e o temporário que criamos.
Exatamente (mas se aplica apenas à inicialização do xref
que vai enlouquecer.Em todos os outros casos, o comportamento pretendido que você deseja (ou o que acredito que você deseja) é alcançado).
Outras dicas
Temporários sempre vivem a vida inteira cheio expressão em que eles são criados de qualquer maneira. Portanto, no declaração de expressão func_val(--getfoo());
, a vida inteira do temporário devolvido pelo getfoo()
A expressão não precisa de nenhuma extensão. A declaração não termina até depois func_val()
voltou.