Solved

typeid() or dynamic_cast causes seg fault in C++ MinGW app

Posted on 2007-12-06
11
1,802 Views
Last Modified: 2010-05-18
I am developing a simple payroll application in c++ using MinGW and wxWidgets. I created a DOS tester just to test my classes before trying to integrate them into my GUI. With my DOS application all the code compiled and executed as I expected. However, when I took my classes and included them in my project with the GUI app, everywhere I used typeid() or tried to use a dynamic_cast, I got a seg fault error and the program terminates. I tested the gui before including the code to make sure it compiled and ran successfully and it worked fine. Other pieces of code that don't use typeid() or use a dynamic_cast also run fine in the gui. I'm completely stumped and running out of time. Quick response is REALLY appreciated!
void Payroll::loadSales()

{

	int empNumber;

	double sales;

	int size = emps.size();

	ifstream inFile("c:\\sales.txt");

	inFile >> empNumber;

	for (int i = 0; i < size; i++)

	{

		if(!inFile.eof())

		{

			if(emps[i]->getEmpNumber() == empNumber)

			{	

				inFile >> sales;

				Sales* sptr;

				if((typeid(*emps[i])) == typeid(Sales))

				{

					sptr = dynamic_cast<Sales*>(emps[i]);

					sptr->setSales(sales);

				}

				inFile >> empNumber;

			}

		} else {

			continue;

		}

	}

}

Open in new window

0
Comment
Question by:rbenbolton
  • 4
  • 2
  • 2
  • +2
11 Comments
 
LVL 28

Expert Comment

by:pepr
Comment Utility
I do not know your compiler, but generally, when using dynamic_cast or typeid(), the Runtime Type Information must be enabled (via the compiler switch). The default for the swithc is usually off. Don't you observe any related warning?
0
 
LVL 28

Accepted Solution

by:
pepr earned 500 total points
Comment Utility
To add, the wxWidgets documentation says:

   "RTTI
    wxWidgets does not use C++ run-time type information
    since wxWidgets provides its own run-time type information
    system, implemented using macros."

Then it is likely that some default wxWidgets project do not switch the RTTI on.
0
 

Author Comment

by:rbenbolton
Comment Utility
I did double-check to make sure that the RTTI was enabled in my project. The original problem I had was that the program would not compile precisely because rtti was not enabled. Once I enabled rtti in the project settings, my project then compiled but then I started getting the seg faults from typeid() and dynamic_cast.

Interestingly enough, I found that static_cast actually worked in my program to do what I needed; however, I still don't think that's the correct usage.

So if I were to use the wxDynamicCast in place of dynamic_cast, how would this be done? I did read some documentation on wxDynamicCast but it only seemed to apply to wxWidget objects. I could be wrong. But if anyone has an example that would be very helpful.
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
I have never used wxDynamicCast, but from the doc it has nothing to do with RTTI and I do not know if it is suitable also for replacing the standard dynamic_cast.

Anyway, dynamic_cast returns NULL when the cast was unsuccessful. You should check the returned value before using the pointer. What kind of pointers is stored inside your emps container?
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
>> Anyway, dynamic_cast returns NULL when the cast was unsuccessful
Yes, if it's a pointer cast, if it's a reference cast it throws the exception std::bad_cast.

Why do you check typeid before the dynamic cast? It's not necessary to do that and is costing you performance. It it's a pointer dynamic_cast returns NULL on failure and if it's a reference it throws (see above).
Also, are you sure the pointers you try to dereference are in fact valid pointers? A SEGV is normally caused by trying to access invalid memory! The dynamic_cast could be a red-herring! Looking at this isolated code sample it is hard really to see what could be wrong with it. I think if I was you I'd put in some asserts to test your assumptions (for example, assert the pointers to see if your assumptions that they are valid is actually correct).
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 28

Expert Comment

by:pepr
Comment Utility
evilrix: The reason for checking typeid may be that the container stores void pointers to more classes that are quite unrelated. However, I do not know if this is the case.
0
 
LVL 17

Expert Comment

by:rstaveley
Comment Utility
If you have...

    sptr = dynamic_cast<Sales*>(emps[i]);
    sptr->setSales(sales);

...you may as well have...

    sptr = reinterpret_cast<Sales*>(emps[i]);
    sptr->setSales(sales);

...because you are saying that you *know* that emps[i] is downcastable to a Sales* and you are not fielding the possibility that it isn't. Using reinterpret_cast<> is quicker and dirtier. When you use it you are saying "I know best".

If you want to handle the possibility that it isn't downcastable, then there is value in the dynamic cast, but do handle the event that it isn't downcastable (i.e. handle failed casts).

e.g.

    sptr = dynamic_cast<Sales*>(emps[i]);
    if (sptr) sptr->setSales(sales);
0
 

Author Comment

by:rbenbolton
Comment Utility
The application I am programming is a simple payroll application and the vector emps is of Employee base class, but holds various derived classes - Salaried, Sales or Hourly object types all derived from the employee base class. I am checking the typeid() simply to verify that the object I want is in fact a Sales object. In this particular case, I could skip that step, as I know from the data I am reading in that it is in fact a Sales object, but there are other functions using similar code where I have to set data members specific to the derived class and must check typeid() to know which derived function to call.

That being said, I found that static_cast actually worked instead and didn't give me the seg faults I was seeing with dynamic_cast. However, the typeid() still throws the seg fault and I had to use a workaround to discover which object type I was dealing with by storing an empType integer in the object and doing a comparison on that.

That being said, I still have no idea why dynamic_cast and typeid() would seg fault while static_cast works.
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> I have to set data members specific to the derived class and must check typeid() to know which derived function to call.

That might be a sign of a bad design ... Usually virtual methods work better in this kind of scenario.
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
>> That might be a sign of a bad design ... Usually virtual methods work better in this kind of scenario.
I agree. If you can't provide abstract/virtual functions in your base class that make sense when used in a sub class context then your class hierarchy is probably wrong. If the design was right you'd have no need to dynamic cast. In fact, the use of dynamic cast can usually be considered a work-around for inadequate design.
0
 
LVL 17

Expert Comment

by:rstaveley
Comment Utility
If dynamic_cast returns a 0, when you are expecting it to downcast, it may be that your object has been "sliced" by passing its base by value rather than by reference in a bit of sloppy polymorphism implementation.

e.g. Where derived is a class derived from a class called base...

--------8<--------
void f(base b) { // Oops forgot to make it a reference
        derived *p = dynamic_cast<derived*>(&b);
        assert(p != 0);
}

{
   derived d;
   f(d);
}
--------8<--------

The sliced object will not be dynamically downcastable, because the copy is not an instance of derived, it is an instance of base.

It is easy to make this mistake if you have a standard library container of base rather than base*.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now