RTTI in a nested class, VS Bug?

The following code outputs:

struct Property<int>::IValue

But I would expect it to print:

struct Property<int>::Value<int>

the code:

 struct IProperty { virtual ~IProperty() = 0; }; IProperty::~IProperty(){} template<typename T> struct Property : IProperty { struct IValue { virtual ~IValue() = 0; }; template<typename Q> struct Value : IValue { Q thing; }; Property() : m_pValue(new Value<T>()){} std::shared_ptr<IValue> m_pValue; }; template<typename T> Property<T>::IValue::~IValue(){} int main() { std::unique_ptr<IProperty> p(new Property<int>); std::cout << typeid(*static_cast<Property<int>&>(*p).m_pValue).name() << '\n'; } 

If IValue and Value move outside the Property , so that they are no longer nested classes, I get the expected results. Is this VS error or expected behavior?

+8
c ++ visual-studio-2010
source share
1 answer

This is definitely a Visual C ++ compiler error. For some strange reason, the compiler cannot determine that Property<T>::IValue dereferenced from shared_ptr is a polymorphic base class and uses static type information to express typeid instead of typeid type information.

Minimum code to reproduce the error:

 template <class T> struct Property { struct IValue { void f() {} virtual ~IValue() = 0 {} }; struct Value: IValue {}; Property(): m_pValue(new Value()) { // typeid inside class works as expected std::cout << "Inside class: " << typeid(*m_pValue).name() << std::endl; } // If changed to unique_ptr typeid will work as expected // But if changed to raw pointer the bug remains! std::shared_ptr<IValue> m_pValue; }; int main() { Property<int> p; // If next line uncommented typeid will work as expected //p.m_pValue->f(); std::cout << "Outside class: " << typeid(*p.m_pValue).name() << std::endl; } 

I played typeid with this sample a bit and found that typeid starts working as expected and displays the name of the runtime type if some function from a pointed object is called before typeid or if shared_ptr is replaced with unique_ptr . It's funny, but replacing shared_ptr<IValue> with IValue* still reproduces the error!

Actual conclusion:

 Inside class: struct Property <int> :: Value
 Outside class: struct Property <int> :: IValue

Expected (correct) conclusion:

 Inside class: struct Property <int> :: Value
 Outside class: struct Property <int> :: Value

From the assembler list, it’s clear that this is really a compiler problem:

typeid called from Property ctor generates an honest call to __RTtypeid :

 ; 225 : std::cout << typeid(*m_pValue).name() << std::endl; ... irrelevant code skipped ... ; __type_info_root_node push OFFSET ?__type_info_root_node@@3U__type_info_node@@A mov ecx, DWORD PTR _this$[ebp] ; std::tr1::shared_ptr<Property<int>::IValue>::operator* call ??D?$shared_ptr@UIValue@?...<skipped> push eax call ___RTtypeid 

typeid , called externally, generates static information of type IValue :

 ; 237 : std::cout << typeid(*p.m_pValue).name() << std::endl; ... irrelevant code skipped ... ; __type_info_root_node push OFFSET ?__type_info_root_node@@3U__type_info_node@@A mov ecx, OFFSET ??_R0?AUIValue@?$Property@H@@@8 

Also note that the same error is present in VS2008, so this is an old time behavior.

+4
source share

All Articles