PDA

View Full Version : Signals destroys my pointer



Jojo
6th March 2006, 20:22
Hello,

I have an odd problem with one of my signals. This is one of the problems where everything used to work yesterday, but now it doesn't.

The problem occurs when I pass a structure by pointer over an interface, when I read the variable in a slot the contents are all garbage.

This is what I'm doing (hope you don't mind reading some code for problem solving ;) :
I am handling a find text functionality, the user pressd a button, the find text dialog triggers a signal, the controller does the search..



// This function emits the problematic signal
void findTextDialog::onFindButtonSlot ()
{
// setup find text event args from dialog
interfaces::eventArgs::findTextEventArg args;
args._findString = ui.findStringTextbox->text();
args._caseSensitive = (ui.matchCaseCheckBox->checkState() == Qt::Checked);
args._wholeWord = (ui.wholeWordCheckbox->checkState() == Qt::Checked);
args._backwards = (ui.findBackwardsCheckbox->checkState() == Qt::Checked);

// This output is all right..
LOG_ERROR (QString("VIEWFIND:1").arg(ui.findStringTextbox->text()).toStdString());

// trigger event in interface
emit interface.onFindTextSignal (&args);
}

// The interface signal:
class interface
{
// This is triggered in the dialog and connected to in the controller
void onFindTextSignal (interfaces::eventArgs::findTextEventArg* searchParameter);
}

// The controller slot handling the finding:
void findReplaceController::findTextSlot (interfaces::eventArgs::findTextEventArg* arg)
{
LOG_ERROR ("BEFORE");

// This gives me garbage OR a crash
LOG_ERROR (QString("SEARCHSTRING: %1").arg(arg->_findString).toStdString());
}

// The structure I am passing
struct findTextEventArg
{
//! Search parameters
QString _findString;
bool _caseSensitive;
bool _backwards;
bool _wholeWord;
};



I hope you can help me with this problem. This code used to work a couple of days ago and I can't see nothing wrong with it. Passing custom types via pointer over interfaces works fine.
The connections are not queued or anything, I don't even get a Qt warning.


Thanks for your help :)

wysota
6th March 2006, 20:26
emit interface.onFindTextSignal (&args);

Hmm... why do you emit.... a method (returning "void" to be even more funny)? Or am I wrong? We don't see any variable declarations, it's hard to say what do you do there at all. I don't see any QObjects or nothing. Are you using Qt signals at all?

Jojo
6th March 2006, 21:47
Hello,

thanks for your reply!

Of course I am using signals and stuff, I just left out the least important bits of information. Of course the interface function is a signal too, I just left it out because I didn't want to spam this topic.

If you say you don't understand what I am doing let me explain it to you quickly:
As said before, I have implemented a "find text" dialog, which allows you to search for text in a QTextEdit.
The first class (findTextDialog) handles the gui stuff of the dialog. The function/slot I have pasted is the slot which gets executed when the user presses the "&Find" button.
The function onFindButtonSlot then emits a signal on an interface.
The interface is a common place where signals for view<->controller interactions are saved. This might seem a little odd at first glance, but it is called a hexagonal MVC pattern, there is no direct contact between view and controller clases at all.
The controller class findReplaceController connects to the specific interface signals when the application starts. It also receives the "find text" signal emitted from the find text dialog.
As parameter some eventargs are passed. This structure saves information about what to search as well as some search options. It is this variable which gets corrupted during transfer over the signals. Like I mentioned before, this is odd because it used to work yesterday (c).
I hope with these explanations and with the new code my problem makes more sense to you than it does to me now ;)

Ok, let's start with a more verbose code dump :

FindTextDialog - The one who emits the signal..


class findTextDialog : public QDialog
{
Q_OBJECT

//
void onFindButtonSlot ()
{
LOG_DEBUG("findTextDialog::onFindButtonSlot");

// setup find text event args from dialog
interfaces::eventArgs::findTextEventArg args;
args._findString = ui.findStringTextbox->text();
args._caseSensitive = (ui.matchCaseCheckBox->checkState() == Qt::Checked);
args._wholeWord = (ui.wholeWordCheckbox->checkState() == Qt::Checked);
args._backwards = (ui.findBackwardsCheckbox->checkState() == Qt::Checked);

LOG_ERROR (QString("VIEWFIND: %1").arg(ui.findStringTextbox->text()).toStdString());
// trigger event in interface
emit getFindTextInterface().onFindTextSignal (&args);

// close dialog
onCancelButtonSlot ();
}
};



The interface - This class stores some signals which controller and view use to communicate


class findTextInterface : public QObject, public genericInterface
{
Q_OBJECT

signals:

//! Signals sent FROM the view TO the controller

/// Start searching for some text.. sent by the find button of the find text dialog
void onFindTextSignal (interfaces::eventArgs::findTextEventArg* searchParameter);
};



FindReplaceController - This is the class which should take care of doing the "find text" logic


/**
@brief Controller class to select(find) and replace text
*/
class findReplaceController : public QObject, public genericController
{
Q_OBJECT
virtual void connectSignals ()
{
// find text
connect (getFindTextInterface(),
SIGNAL(onFindTextSignal(interfaces::eventArgs::fin dTextEventArg*) ),
this, SLOT(findTextSlot(interfaces::eventArgs::findTextE ventArg*)));

}

public slots:
/**
@brief Called from the view, this finds some text in the front file in the editor
*/
void findTextSlot interfaces::eventArgs::findTextEventArg* arg)
{
// This crashes sometimes or gives bad data
LOG_ERROR (QString("SEARCHSTRING: %1").arg(arg->_findString).toStdString());

}
};



FindTextEventArgs - This is passed over the interface from the view


struct findTextEventArg
{
//! Search parameters
QString _findString;
bool _caseSensitive;
bool _backwards;
bool _wholeWord;
};



Thanks for help and replies,
Bye, Headhunter

(Hope the forum doesn't kill my beautiful code intendention)

wysota
7th March 2006, 00:03
Of course I am using signals and stuff, I just left out the least important bits of information.
Or the most important ones.


Of course the interface function is a signal too, I just left it out because I didn't want to spam this topic.
(...)
The function onFindButtonSlot then emits a signal on an interface.
The interface is a common place where signals for view<->controller interactions are saved.
You can't emit signals from other objects. You have to provide wrappers, like so:

class someclass : public QObject{
Q_OBJECT
public:
void emitSignal1(){ emit signal1(); }
void emitSignal2(){ emit signal2(); }
signals:
void signal1();
void signal2();
//...
};


This might seem a little odd at first glance, but it is called a hexagonal MVC pattern, there is no direct contact between view and controller clases at all.
As far as I understand, Qt signals/slots do just that on their own.


The controller class findReplaceController connects to the specific interface signals when the application starts. It also receives the "find text" signal emitted from the find text dialog.
(...)

You are making it very complex... too complex, I think.

If you have to make things complex (but still working), a signal proxy might help you. One of the issues of Qt Quarterly describes that.


(Hope the forum doesn't kill my beautiful code intendention)
Don't worry, the forum didn't kill anything yet, so it won't kill your indentation.

Jojo
7th March 2006, 08:10
Hello,

I know the hexagonal MVC pattern is a bit heavy.. but that's the way I decided to go, and it actually works out quite fine.
I don't need signal proxys, because (don't hit me) I "#define protected public" before each signal. Works fine, and I don't need emitters.
But do you have any ideas about the problem?

wysota
7th March 2006, 11:08
I don't need signal proxys, because (don't hit me) I "#define protected public" before each signal. Works fine, and I don't need emitters.
This behaviour is not documented anywhere (meaning its implementation dependent), so one day your code might just stop working.


But do you have any ideas about the problem?
I'll ask my question again :) Why don't you use references instead of pointers?

void onFindTextSignal (interfaces::eventArgs::findTextEventArg &searchParameter);

BTW. Are the emitter and receiver in the same thread? Which Qt version are you using?

Jojo
7th March 2006, 12:17
Hello,

thanks for your answer.
I am using pointers because passing by reference does not work. QObject gives me a warning at runtime, telling me the parameter can not be queued. Registering my custom type to the Qt Metasystem should work, but it doesn't. So I use pointers.
This problem occurs with Qt 4.1.0 and with the previous version too.
I use a single threaded application, the signals are not queued either.
Odd, isn't it ;) ?

wysota
7th March 2006, 15:45
Registering my custom type to the Qt Metasystem should work, but it doesn't.
What errors do you get?

seneca
7th March 2006, 16:53
What you are trying to do will obviously fail when the signal is queued. You are creating an object 'args' within the method 'onFindButtonSlot' and sending it's address by the signal. However that object is deleted at the end of 'onFindButtonSlot' and when your queued signal is processed later it is allready destroyed.

Jojo
7th March 2006, 19:26
Hello,

I have set the signal explicitly to a direct connection, and now my search function works like a charm. I really can't explain why, I am not using threads, and I am always calling connect without any extra connection type parameters.

Now I have another problem. My application will terribly crash if signal connections are not direct. I haven't noticed any strange crash yet, but who knows.

What shall I do now? Explictly set DirectConnection to each connect line? Set a nondocumented flag in QApplication to disable implicit multithreading? I'm again very clueless about Qt's behaviour..

Thanks for advice again :)

wysota
7th March 2006, 20:44
Don't use pointers to temporary objects. Either make those structures heap based or don't use pointers at all. I'm still curious what errors did you get while trying to use a reference... Maybe you forgot the magic "const" keyword? It is possible if you wanted to reference a temporary object.

Jojo
7th March 2006, 21:05
Don't use pointers to temporary objects. Either make those structures heap based or don't use pointers at all. I'm still curious what errors did you get while trying to use a reference... Maybe you forgot the magic "const" keyword? It is possible if you wanted to reference a temporary object.

Hello,
I need pointers to objects. As I said before, passing custom types over signals only works when I pass them via pointer.
I don't think passing the pointer as const would help much. As far as I see it, Qt signal parameters are passed by value just like in Java or in .NET. I can't see a constant pointer help much there.
Passing a pointer for a temporary object is fine in my case, because the controller creates a copy of the passed object, so the temporary object pointer is only accessed once, when the object is still well defined.

I don't get any errors when accessing the passed pointer. Since when tells C++ errormessages when you do something wrong ;)
What happens is, that the received pointer is garbage.
Use "int* a; int b = *a+4" for a similar experience. Either your programm crashes or you receive some weird values..

Still the question remains, why does Qt make my signal calls asynchronous? This is poison for my application!

wysota
7th March 2006, 22:05
As I said before, passing custom types over signals only works when I pass them via pointer.

But what does "not work" mean?


I can't see a constant pointer help much there. I meant a constant reference.


Passing a pointer for a temporary object is fine in my case, because the controller creates a copy of the passed object, so the temporary object pointer is only accessed once, when the object is still well defined.

Not with asynchronous calls.