Comunidade
cancelar
Mostrar resultados para 
Pesquisar em vez de 
Queria dizer: 
Highlighted
Principiante
67 Visualizações

dynamic_cast troubles

Hello.This code throws an exception when compiled with ICC 12.1.5 (works fine with MSVC and GCC):[cpp]class A { public: virtual void _dummy() { } }; class B: virtual public A { }; class C: virtual public A, public B { }; int main() { auto c = new C; auto a = dynamic_cast< A * >( c ); auto b = dynamic_cast< B * >( c ); auto ca = dynamic_cast< C * >( a ); // ok auto cb = dynamic_cast< C * >( b ); // std::__non_rtti_object return 0; } [/cpp] The culprit seems to be the "class B: virtual public A" part. Just "class B: public A" works without exceptions.----Regards,Vladimir

27 Respostas
Highlighted
Funcionário
65 Visualizações

I'm not catching any exceptions with this code. What compiler options are you using to build, and how exactly are you determining that the __non_rtti_object exception is being thrown?
Highlighted
Principiante
65 Visualizações

Just "icl test.cpp" produces an executable that crashes. The exception itself shows up when debugging this from under Visual Studio.
Intel C++ Compiler XE for applications running on IA-32, Version 12.1.5.344 Build 20120612
for Windows
Highlighted
Principiante
65 Visualizações

I'm not catching any exceptions with this code. What compiler options are you using to build, and how exactly are you determining that the __non_rtti_object exception is being thrown?

Hi Brandon,

were you able to reproduce the issue?

----
Vladimir

Highlighted
Contribuidor valorado II
65 Visualizações

Vladimir, Brandon,

Did you compile the test-case without modifications? I could not compile... So, please take a look at amodified test-case:
[cpp] ... C *pC = new C; A *pA = dynamic_cast< A * >( pC ); B *pB = dynamic_cast< B * >( pC ); C *pCA = dynamic_cast< C * >( pA ); C *pCB = dynamic_cast< C * >( pB ); ...[/cpp]I'm still investigating and will provide some technical details later.

Best regards,
Sergey
Highlighted
Principiante
65 Visualizações

Sergey,

I compiled the original code sample without modifications using the ICC version specified a few posts above. Removing dependency on C++11 as per your modifications results in the same outcome.
I do not know if this problem is reproducible on other compiler versions.Which version did you use?
BTW, the issue is reproducible for both 32- and 64-bit executables.
----
Regards,
Vladimir
Highlighted
Contribuidor valorado II
65 Visualizações

Quoting vpozdyayev
I compiled the original code sample without modifications...


Hi Vladimir,

In your original post you've stated that the test case"...works fine with MSVC...". I understood that you've compiled it with
some version of Visual Studio. Did you use 2005, 2008, 2010 or 2012 vesrion?

In case ofMicrosoft C++ compiler and Visual Studio 2005 I can't compile
...
auto c = new C;
...
because it doesn't support C++11. I simply wanted to verify howthe testworks when it is compiled with Microsoft C++ compiler.

Could you provide more details on your software development environment? Thanks in advance.

Best regards,
Sergey

PS: Here are compilation errors I have:

..\PrtTests.cpp(5710) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
..\PrtTests.cpp(5710) : error C2440: 'initializing' : cannot convert from 'C *' to 'int'

Highlighted
Contribuidor valorado II
65 Visualizações

Hi Vladimir,

I hope thata modified test-case for a 'dynamic_case' C++ operator will be useful for you ( it is amore generic ):

...
class A
{
public:
virtual void Method( void )
{
printf( "A::Method\n" );
};
};

class B: virtual public A
{
public:
virtual void Method( void )
{
printf( "B::Method\n" );
};
};

class C: virtual public A, public B
{
virtual void Method( void )
{
printf( "C::Method\n" );
};
};

class D
{
public:
virtual void Method( void )
{
printf( "D::Method\n" );
};
};
...
C *pC = new C;

A *pA = dynamic_cast< A * >( pC );
printf( "Object A is%sinitialized\n", ( pA !=NULL ) ? " " : " NOT " );

B *pB = dynamic_cast< B * >( pC );
printf( "Object B is%sinitialized\n", ( pB !=NULL ) ? " " : " NOT " );

C *pCA = dynamic_cast< C * >( pA );
printf( "Object C is%sinitialized\n", ( pCA !=NULL ) ? " " : " NOT " );

C *pCB = dynamic_cast< C * >( pB );
printf( "Object C is%sinitialized\n", ( pCB !=NULL ) ? " " : " NOT " );

D *pD = dynamic_cast< D * >( pC );
printf( "Object D is%sinitialized\n", ( pD !=NULL ) ? " " : " NOT " );
...

Highlighted
Principiante
65 Visualizações

Hi Sergey,
the original post was about executables produced by ICC + MSVC 2010 SP1 IDE. However, the same results can be observed with ICC + MSVC 2008 IDE, and any command line combination of "(IA-32|Intel 64) Visual Studio (2008|2010) mode". OTOH, compiling this code with MSVC itself does not result in any exceptions. (For compiling with VC 2008, an "auto"-less version like the one you have suggested is necessary.)
----
Regards,
Vladimir
Highlighted
Contribuidor valorado II
65 Visualizações

Hi Vladimir,

Have you noticed that I've added a new class D andthen tried to castthe pointerof the class Cto the pointer ofclassD?

A very important feature of the 'dynamic_cast'isthat itshould not cast fromtypeC to type D andthepointer to the object oftype D
must be equal toNULL.

However, I think that something is wrong with Intel C++ compiler because your original test-case is very generic even if it uses
some C++11 features. I wonder if thereissome problem related to support ofC++11 features in the compiler?

Best regards,
Sergey
Highlighted
Principiante
65 Visualizações

Hi Sergey.

As it appears, the issue doesn't seem to be related to C++11 support; it shows up with "C *pC = ..." instead of "auto pC = ...", as well.

An interesting point demonstrated by your code example is that the issue depends on the presence of virtual functions in different classes. I have tried a few combinations:

  • Dynamic cast from B* to C* raises an exception when B does not declare/define any virtual functions, but does NOT fail if it does (concrete or pure functions, doesn't matter).
  • Likewise, dynamic cast from C* to D* raises an exception when C declares/defines no virtual functions, and works fine otherwise.
  • The issue disappears if we add a virtual destructor to A (and, by extension, implicitly generated virtual destructors to its descendants).

It looks like ICC has a problem with empty vtables (or, rather, empty additions to vtables provided by the original classes B and C).

----
Regards,
Vladimir
Highlighted
Contribuidor valorado II
65 Visualizações

Quoting vpozdyayev
...As it appears, the issue doesn't seem to be related to C++11 support; it shows up with "C *pC = ..." instead of "auto pC = ...", as well...

[SergeyK] I've done a verification with two more C++ compilers ( MinGW & Borland )andthere are no anyissues or problems.

An interesting point demonstrated by your code example is that the issue depends on the presence of virtual functions in different classes. I have tried a few combinations:

  • Dynamic cast from B* to C* raises an exception when B does not declare/define any virtual functions, but does NOT fail if it does (concrete or pure functions, doesn't matter).
  • Likewise, dynamic cast from C* to D* raises an exception when C declares/defines no virtual functions, and works fine otherwise.

    [SergeyK] It shouldn't raise any exceptions and it should assign a valueNULL to apointer of type D.

Highlighted
Contribuidor valorado II
65 Visualizações

Hi Vladimir, Could you try a newtest-case?Instead of 'dynamic_cast'

Quoting Sergey Kostrov
...
C *pC = new C;


A *pA = dynamic_cast< A * >( pC );
printf( "Object A is%sinitialized\n", ( pA !=NULL ) ? " " : " NOT " );

B *pB = dynamic_cast< B * >( pC );
printf( "Object B is%sinitialized\n", ( pB !=NULL ) ? " " : " NOT " );

C *pCA = dynamic_cast< C * >( pA );
printf( "Object C is%sinitialized\n", ( pCA !=NULL ) ? " " : " NOT " );

C *pCB = dynamic_cast< C * >( pB );
printf( "Object C is%sinitialized\n", ( pCB !=NULL ) ? " " : " NOT " );

D *pD = dynamic_cast< D * >( pC );
printf( "Object D is%sinitialized\n", ( pD !=NULL ) ? " " : " NOT " );
...


use a"default" cast, like:

...

C *pC = new C;


A *pA = ( A * )pC;
printf( "Object A is%sinitialized\n", ( pA !=NULL ) ? " " : " NOT " );

B *pB = (B * )pC;
printf( "Object B is%sinitialized\n", ( pB !=NULL ) ? " " : " NOT " );

C *pCA = ( C * )pA;
printf( "Object C is%sinitialized\n", ( pCA !=NULL ) ? " " : " NOT " );

C *pCB = ( C * )pB;
printf( "Object C is%sinitialized\n", ( pCB !=NULL ) ? " " : " NOT " );

D *pD = (D * )pC;
printf( "Object D is%sinitialized\n", ( pD !=NULL ) ? " " : " NOT " );
...

Highlighted
Principiante
65 Visualizações

Hi Sergey.
C-style casts work reasonably enough, with "(C*)pA" giving a "cannot convert" compile-time error, and "(D*)pC" resulting in an unusable pointer. The trouble is only with one particular dynamic_cast, whereFindCompleteObject(void**) encounters a null pCompleteLocatorand throws the "Access violation - no RTTI data!"__non_rtti_objectexception.
----
Best regards,
Vladimir
Highlighted
Contribuidor valorado II
65 Visualizações

Hi Vladimir,

Quoting vpozdyayev
Hi Sergey.
C-style casts work reasonably enough, with "(C*)pA" giving a "cannot convert" compile-time error, and "(D*)pC" resulting in an unusable pointer. The trouble is only with one particular dynamic_cast, whereFindCompleteObject(void**) encounters a null pCompleteLocatorand throws the "Access violation - no RTTI data!"__non_rtti_objectexception.
----
Best regards,
Vladimir


I really don't understand whyIntel C++ compilerneeds RTTI for the test-case.

Highlighted
Principiante
65 Visualizações

Hi Sergey,

this test case doesn't need RTTI and works OK. The part about "one particular dynamic_cast" was referring to the original code sample, sorry for confusion.
----
Regards,
Vladimir
Highlighted
Principiante
65 Visualizações

Gentlemen,
the original test case still fails on ICC 2013 update 2, command line (with just "icl.exe test.cpp"), or under MSVS 2012, x86 and x64. Any luck reproducing the issue?

----
Regards,
Vladimir 

Highlighted
Contribuidor valorado II
65 Visualizações

>>...the original test case still fails on ICC 2013 update 2, command line (with just "icl.exe test.cpp"), or under MSVS 2012, >>x86 and x64 Hi Vladimir, I regret to see that the problem is still not fixed. So, I'll do another set of tests with ICC 2013 Initial Release integrated with VS 2008 Professional Edition. Best regards, Sergey
Highlighted
Contribuidor valorado II
65 Visualizações

>>...I'll do another set of tests with ICC 2013 Initial Release integrated with VS 2008 Professional Edition... Here are results: There is a problem with Intel C++ Composer XE 2013 ( 2013.0.089 / Initial Release ) when the following code is executed: ... auto cb = dynamic_cast< C * >( b ); ... A 32-bit test application crashes in a malloc CRT-function ( Debug and Release configurations ) because nSize is equal to 3765269347 and this is exactly 3GB (!): ... extern "C" _CRTIMP void * __cdecl malloc( size_t nSize ) { void *res = _nh_malloc_dbg( nSize, _newmode, _NORMAL_BLOCK, NULL, 0 ); RTCCALLBACK( _RTC_Allocate_hook, ( res, nSize, 0 ) ); return res; } ... and the exception is thrown from _nh_malloc_dbg internal CRT-function. I think nSize should have a value 4. I couldn't reproduce the problem with Microsoft C++ compiler of Visual Studio 2012 Express Edition.
Highlighted
Contribuidor valorado II
65 Visualizações

Here is a screenshot:
dyncastproblem.jpg