As I understand temporaries, the following code should work, but it doesn't.
struct base
{
virtual~base() {}
virtual void virt()const=0;
};
struct derived:public base
{
virtual void virt()const {}
};
const base& foo() {return derived();}
int main()
{
foo().virt();
return 0;
}
The call to virt() gives a "pure virtual function called" error. Why is that, and what should I do?
It seems like you're expecting the const
reference to extend the lifetime of the temporary. There are certain situations where this doesn't occur. One of those situations is when returning a temporary:
The second context [in which temporaries are destroyed at a different point than the end of the full-expression] is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
[...]
- The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
Since calling a member function of the object returned by foo()
will necessitate an lvalue-to-rvalue conversion and the object is invalid (not derived from type base
), you get undefined behaviour:
If the object to which the glvalue refers is not an object of type
T
and is not an object of a type derived fromT
, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.