QtCreator 3.1.1 (Qt 5.2.1) virtual method causes segmentation fault
-
Hi guys, this may solve my "segmentation fault" question that I have raised earlier, but I am not sure yet... Something came across my mind with regard to virtual methods. In my project I have a general device that has 5 subclasses and holds pointers to one instance to each of the 5 and one pointer as a copy of one of the 5 as the currently active device. For simplification I will only post 2 of the 5 subclasses.
Here are the headers, they are in single files, but I think this reads better:
class wbstlDevice : public QObject { public: wbstlDevice( QObject *parent = 0 ); virtual ~wbstlDevice(); virtual unsigned int rfPower4x1Length(); // returns length in indices! One index contains 6 bytes / 12 nibbles wbstlDevice *currentDevice, *deviceSRX1G9, *deviceSRX2G4; ... }; class wbstlDevPRX1G9 : public wbstlDevice { public: wbstlDevPRX1G9(); ~wbstlDevPRX1G9(); unsigned int rfPower4x1Length(); }; class wbstlDevPTX1G9 : wbstlDevice { public: wbstlDevPTX1G9(); ~wbstlDevPTX1G9(); unsigned int rfPower4x1Length(); };
Pretty simple, the same with the cpp files:
unsigned int wbstlDevice::rfPower4x1Length() { return 0; } unsigned int wbstlDevPRX1G9::rfPower4x1Length() { return 2; } unsigned int wbstlDevPTX1G9::rfPower4x1Length() { return 4; }
I THOUGHT I understood virtual functions / methods, but now I am not that sure any more. In my code I have (as test) these both lines:
a = device.currentDevice->getChannelFreqMHz( idx ); a = device.getChannelFreqMHz( idx );
They are directly below each other, so I don't see an issue with multithreading, access, idx, etc. Now, the second line works fine while the first one causes a segmentation fault.
Can anyone tell what the issue could be???
Thanks a lot,
Stephan -
As with your segfault-problem it would no be possible to find an error in some code-fragments if you dont show the whole sourcecode. You talk about an error in "getChannelFreqMHz", but this part is not shown. Also the code about creating the objects and accessing them before the error occurs isn't there. The only issue that can be seen here is using an QObject-derived class without the Q_OBJECT macro.
As you are fighting with this error a long time now you should really try to create a small testproject that reproduces the error and publish this completly.
Regards
gerd -
@Gerd
In addition to what you said about QObject-derived class, sometimes, when one adds the Q_OBJECT macro on the fly, the moc files are not recompiled, resulting in some errors about virtual methods. Then the solution consists in removing the build content, run qmake, and recompile. -
To solve this we need source code...
Anyway is NEVER a good idea to have public pointer members; your problem is this; a pointer is not initialized and being public it is only making that worse (since it can be modified without control everywhere in your code)! -
Ok, sorry for holding back the overall code, it actually contains about 20 header/source files each with the biggest one having 2,5k LOC, so I thought stripping it down makes sense. I must admit I have avoided creating an all new project because I am not really sure what to include there and what not. But I definitely see the point in it!
But I can surely show the parts you have been asking about. Sorry about my fault with the function call. With respect to the extract I have shown the lines that show the same error as described are these:
device.currentDevice->rfPower4x1Length(); device.rfPower4x1Length();
I had only included the other calls in my project to figure out why some other calls to virtual methods work. But I wasn't able to find that, so the extract is, that I don't know why these calls cause a error?
The device is now created in the constructor of the main window:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), device(this) {
while it is destroyed implicitly. The constructor of the device looks like this:
wbstlDevice::wbstlDevice( QObject *parent ) { if ( parent != 0 ) { devicePRX1G9 = (wbstlDevice*) new wbstlDevPRX1G9(); devicePTX1G9 = (wbstlDevice*) new wbstlDevPTX1G9(); } else { devicePRX1G9 = 0; devicePTX1G9 = 0; } currentDevice = NULL; }
Then, obviously, the "currentDevice" will occasionally receive the known pointers to one of the devices. So there is already a lot of stuff around...
bool wbstlDevice::initDevice() { unsigned int id; if ( initialized ) { errorString = "The device was already initialized; can only be done once."; return false; } if ( ( deviceId == WbstlConst::ID_INVALID ) | ( marketId == WbstlConst::ID_INVALID ) | ( rfId == WbstlConst::ID_INVALID ) ) { errorString = QString( "Initialyzing the device is not possible due to invalid ids (%1, %2, %3)" ).arg( (int) deviceId ).arg( (int) marketId ).arg( (int) rfId ).toLatin1(); return false; } id = ( deviceId << 8 ) + marketId; switch ( id ) { case 0x0101: devketId = 0x02; currentDevice = deviceSRX2G4; break; case 0x0104: devketId = 0x01; currentDevice = deviceSRX1G9; break; case 0x0202: devketId = 0x03; currentDevice = devicePRX1G9; break; case 0x0301: devketId = 0x06; currentDevice = devicePTX2G4; break; case 0x0302: devketId = 0x05; currentDevice = devicePTX1G9; break; case 0x0304: devketId = 0x04; currentDevice = devicePTX1G9; break; case 0x0401: devketId = 0x09; currentDevice = devicePTX2G4; break; case 0x0402: devketId = 0x08; currentDevice = devicePTX1G9; break; case 0x0404: devketId = 0x07; currentDevice = devicePTX1G9; break; default: errorString = QString( "Conversion to devket id from %1 and %2 is not possible." ).arg( (int) deviceId ).arg( (int) marketId ); devketId = 0x00; } // Check the combination from devketId and rfId to be valid if ( ( devketId > 0x00 ) & ( !wbstlFuncs::IS_DEVICETYPE_FREQRANGE_COMBI_VALID( devketId, rfId ) ) ) { errorString = QString( "Device combination of \"%1\" and range \"%2\" is invalid, conversion will not be processed!" ).arg( wbstlFuncs::GET_DEVICE_TEXT2( devketId ) ).arg( wbstlFuncs::GET_RF_TEXT_LONG( rfId ) ); return false; } qDebug( QString( "Device was successfully initiated from ids %1, %2, %3 to DevKetId %4" ).arg( (int) deviceId ).arg( (int) marketId ).arg( (int) rfId ).arg( (int) devketId ).toLatin1() ); initialized = true; return true; }
I also checked for destruction of the dynamic objects, but it only occurs at the end of the execution and - in this case - such never because of the segmentation fault. Especially the "device" object is my main data store so it receives over 100 accesses, I don't think its helpful to post them all?
And where the error occurs; there isn't really much around, its like this:
if ( svcCmd == SVC_CMD_GET_RF_POWER_4X1 ) { rfPower4x1.clear(); rfPower4x1.append( data ); val = device.rfPower4x1Length();
The local rfPower4x1 is not related to the device whereas the "device.rfPower4x1Length()" while "device.currentDevice->rfPower4x1Length()" does not work.
I don't know if that helps further understand the issue?
Thanks a lot for your time,
Stephan -
@AlterX Ok, I see, I will change this for the device internal pointers, but the "currentDevice" is used many times from outside to access that data. That's why I kept it public, I didn't really see much sense it making that private and then allow to read it anyway. I see the issue of it being written from outside, but I checked all occurences and they all solely query data and call methods, so I didn't think it helps me with the segmentation fault, what do you think?
Stephan