#include <iostream>
struct A{
A(int){
}
~A(){
std::cout<<"A destroy\n";
}
};
struct B{
B(int){
std::cout<<"B construct\n";
}
~B(){
std::cout<<"B destroy\n";
}
};
struct Content{
A const& a;
};
struct Data{
Data():c{0},b{0}{
}
Content c;
B b;
};
int main(){
Data d;
std::cout<<"exit\n";
}
The output of GCC is:
B construct
A destroy
exit
B destroy
Clang complains this code is ill-formed. Here is the performance of two compilers.
About the error that Clang reports, there's indeed a relevant rule in the standard, that is:
[class.init#class.base.init-8]
A temporary expression bound to a reference member in a mem-initializer is ill-formed.
I'm not sure whether Clang has overunderstood it? In my mind, the rule seems to say that the reference member named by mem-initializer-id of the mem-initializer shouldn't be bound to a temporary expression. In my example, the member c of class Data is not a reference.
Presumably, Clang consider it as that any initialization of reference member which makes the reference member be bound to a temporary expression occurs in a member-initializer are all ill-formed. So I gave a example to examine whether Clang think so.
struct A{
int const& rf;
};
struct B{
B():a(new A{0}){}
A* a;
};
int main(){
B b;
delete b.a;
}
It gives a warning but not an error. So, I'm not sure Clang think so. I don't know how does it understand the rule?
If the first example itself is valid, I will consider GCC does not obey the standard. Because the order of destroying the temporary object.
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
The temporary object would be otherwise destroyed in the end of the full-expression which is the member-initializer, in my example, that is c{0}. However, GCC destroys the temporary object after the subobject b has constructed. I think here is a first issue.
Actually, the temporary be bound the the reference is not the exception listed here:
[class.temporary#6]
The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference
The exceptions to this lifetime rule are:
- A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.
- A temporary object bound to a reference element of an aggregate of class type initialized from a parenthesized expression-list ([dcl.init]) persists until the completion of the full-expression containing the expression-list.
- The lifetime of a temporary bound to the returned value in a function return statement ([stmt.return]) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
- A temporary bound to a reference in a new-initializer ([expr.new]) persists until the completion of the full-expression containing the new-initializer.
Neither, that is, my first example is not exception listed in the above list. Hence, the lifetime of the temporary object should be the same as the lifetime of the subobject a of subobject c of the object b, they all have the same lifetime as that of b. So, why GCC destroy the temporary object so early? Shouldn't the temporary object be destroyed together with the object b in main? I think here is the second issue of GCC. I don't know how Clang process the temporary object, since it has gave an error earlier.
Question:
Is that
Clangreports an error for the first example Right? If it's right, Should [class.init#class.base.init-8] be more clear for that?If
Clangoverunderstand [class.init#class.base.init-8], Is the performance ofGCCof destroying the temporary object be considered as a bug? Or, theexceptionsomiss this case? Even though the exceptions omiss this case(reference binding occurs in member-initializer), I still thinkGCChas wrong, Shouldn't the temporary be destroyed at the end of full-expression(c{0}) which is sequenced before constructingb.
How to interpret these questions in the above?