copy elision: move constructor não chamado ao usar a expressão ternária na instrução de retorno?
Considere o seguinte exemplo:
#include <cstdio>
class object
{
public:
object()
{
printf("constructor\n");
}
object(const object &)
{
printf("copy constructor\n");
}
object(object &&)
{
printf("move constructor\n");
}
};
static object create_object()
{
object a;
object b;
volatile int i = 1;
// With #if 0, object's copy constructor is called; otherwise, its move constructor.
#if 0
if (i)
return b; // moves because of the copy elision rules
else
return a; // moves because of the copy elision rules
#else
// Seems equivalent to the above, but behaves differently.
return i ? b : a; // copies (with g++ 4.7)
#endif
}
int main()
{
auto data(create_object());
return 0;
}
E considere este bit a partir do C ++ 11 Working Draft, n3337.pdf, 12.8 [class.copy], ponto 32:
Quando os critérios para a elisão de uma operação de cópia forem atendidos ou forem atendidos, exceto pelo fato de que o objeto de origem é um parâmetro de função,e o objeto a ser copiado é designado por um lvalue, a resolução de sobrecarga para selecionar o construtor para a cópia é executada primeiro como se o objeto fosse designado por um rvalue. Se a resolução de sobrecarga falhar ou se o tipo do primeiro parâmetro do construtor selecionado não for uma referência de valor para o tipo do objeto (possivelmente qualificada para cv), a resolução de sobrecarga será executada novamente, considerando o objeto como um lvalue. [Nota: Esta resolução de sobrecarga de dois estágios deve ser executada independentemente de a elisão da cópia ocorrer. Ele determina o construtor a ser chamado se a elisão não for executada e o construtor selecionado deve estar acessível mesmo se a chamada for elidida. - end note]
Assim, se usarmos#if 1
No exemplo, o construtor de movimento é tentado pela primeira vez ao retornar o objeto e, em seguida, o construtor de cópia. Como temos um construtor de movimento, ele é usado no lugar do construtor de cópia.
No ultimoreturn
declaração emcreate_object()
No entanto, observamos que o construtor de movimentação não é usado. Isso é ou não é uma violação das regras da linguagem? A linguagem requer que o construtor de movimento seja usado no últimoreturn
declaração?