Link to home
Start Free TrialLog in
Avatar of rbenbolton
rbenbolton

asked on

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

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

Avatar of pepr
pepr

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?
ASKER CERTIFIED SOLUTION
Avatar of pepr
pepr

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of rbenbolton

ASKER

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.
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?
>> 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).
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.
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);
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.
>> 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.
>> 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.
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*.