I found a strange behavior running this small snippet of code compiled with clang:
#include <iostream>
#include <exception>
#include <typeinfo>
struct Foo : public std::exception {
std::string myString;
Foo(const std::string& str) : myString(str) {}
Foo() : Foo(typeid(*this).name()) {}
};
int main()
{
Foo f;
std::cout << f.myString;
}
The instruction typeid(*this).name()
called inside the delegated constructor returns a nullptr
that causes a segmentation fault. During the delegated constructor call std::exception
base class is not yet initialized and this seems the cause of this behavior.
I'm wondering if this code is ill-formed for some reason, or this behavior is expected.
I cannot reproduce this bug with g , where the code runs fine.
It also occurs only if the base class is std::exception, in any other case it works fine even on clang.
CodePudding user response:
This has undefined behavior. typeid
is allowed to be applied to the object under construction in the constructor, also the member initializer list, but only after construction of all base class subobjects has completed. See [class.base.init]/16.
If typeid(*this)
was used after the base classes have been constructed, then [class.cdtor]/5 would describe the behavior of typeid
in this specific situation. (It would return the type_info
corresponding to Foo
irregardless of whether Foo
is the most-derived type.)
I think this is only supposed to apply though if *this
has polymorphic type, i.e. Foo
has a (inherited) virtual member function (std::exception::what
and std::exception::~exception
in your case). The current wording doesn't seem to clearly separate this, but for non-polymorphic types the expression shouldn't even be evaluated, so it can't matter that *this
refers to the object under construction. There are related open CWG issues, e.g. CWG issue 1517.