I am working on developing a Qt application for windows platform. I am facing problem when using exception handling in class hierarchy.
I have Class B object instantiated in a function of Class A. When, due to some reason, an exception is thrown from Class B (and not caught in Class B) it is not being caught in Class A (appropriate try-catch block is present in Class A) and instead the application crashes showing some windows specific error. This type of try-catch mechanism in class hierarchy works perfectly fine in Java.
Example:
This is piece of code of ClassA that is instatiating an object of ClassB (Qt Dialog)
void Class A::on_pbCallB_clicked()
{
try
{
objClassB = new ClassB();
objClassB->show();
}
catch(QString *strExceptionMsg)
{
QMessageBox::critical(this,"Error",*strExceptionMsg);
exit(1);
}
catch(...)
{
QMessageBox::critical(this,"Error","Uknown Error");
exit(1);
}
}
When ClassB dialog is displayed and a button present on the dialog is pressed following piece of code is called:
void ClassB::on_pbThrowExp_clicked()
{
try
{
throw (new QString("Throwing Exception !"));
}
catch(QString *strExceptionMsg)
{
throw strExceptionMsg;
}
catch(...)
{
throw (new QString("Unknown Error"));
}
}
This throws an exception which is caught in ClassB's function but when thrown further it is not caught in ClassA (From where objClassB is instantiated) and the entire application crashes.
I have tried 1 solution where I have re-implemented QApplication’s notify method where, an exception thrown from somewhere in the application, if not caught anywhere, is being caught in re-implemented notify method. But doing this does not stop the application from closing down.
Please confirm if this is even possible in Qt/C++ and if not please point me in direction of an alternative (if available) in Qt.
This is an old question, but since there still might be people trying to combine Qt with exception handling, following is a solution that worked for me. It requires c++11 support though.
application.hpp:
#ifndef APPLICATION_HPP
#define APPLICATION_HPP
#include <QApplication>
#include <exception>
///
/// This class catches any exceptions thrown inside proc()
/// and shows them using the message() function.
/// The virtual message() function can be overriden to customize
/// how the messages are shown. The default implementation
/// shows them using QMessageBox.
///
class Application: public QApplication
{
public:
Application(int& argc, char* argv[]);
bool notify(QObject* receiver, QEvent* event);
virtual int proc() { return exec(); }
int run();
virtual int message(const std::string&);
private:
std::exception_ptr _M_e = nullptr;
};
#endif // APPLICATION_HPP
application.cpp
#include "application.hpp"
#include <QMessageBox>
Application::Application(int& argc, char* argv[]):
QApplication(argc, argv)
{ }
int Application::run()
{
try
{
int code = proc();
// Check if an exception was thrown and stored in Application::notify
// and if so, rethrow it.
if(_M_e) std::rethrow_exception(_M_e);
return code;
}
catch(std::exception& e)
{
return message(e.what());
}
}
int Application::message(const std::string& message)
{
QMessageBox::critical(0, "Error", QString::fromStdString(message));
return 1;
}
///
/// Qt does not allow exceptions thrown from event handlers
/// to be processed outside the event loop.
/// So we catch them here, store them in _M_e
/// and tell the application to exit.
///
bool Application::notify(QObject* receiver, QEvent* event)
{
try
{
return QApplication::notify(receiver, event);
}
catch(...)
{
_M_e = std::current_exception();
exit();
}
return false;
}
You can use the Application class as you would the QApplication, except call the run function instead of exec. (Alternatively, rename run into exec to hide QApplication's exec.)
You can override the message function to customize error messages. You can also override the proc function to add some initialization/destruction code before/after exec.
Related
Hi,
I've got a SIGSEGV when I want to use a QTcpSocket with the following code. (more explanation at the very bottom)
Function to create a QTTCPSocket (which will keep the QTcpSocket pointer):
std::shared_ptr<QTTCPSocket> createQtSocket(std::string host, unsigned int port)
{
QTcpSocket *sock = new QTcpSocket;
sock->connectToHost(QHostAddress(QString::fromStdString(host)), port);
if (!sock->waitForConnected())
throw std::runtime_error("Connection refused");
return std::make_shared<QTTCPSocket>(sock);
}
QTTCPSocket class:
class QTTCPSocket {
public:
QTTCPSocket(QTcpSocket *socket)
: _socket(socket)
{};
~QTTCPSocket() = default;
void send(const std::string &msg)
{
std::cout << msg << std::endl;
_socket->write(&msg[0], static_cast<qint64>(msg.length())); // produces a SIGSEGV if called from a qt event (a button for example)
_socket->waitForBytesWritten(0);
}
private:
QTcpSocket *_socket;
};
Main function:
int main()
{
std::shared_ptr<QTTCPSocket> socket = createQtSocket("127.0.0.1", 33333);
ViewStateMachine vsm(socket);
vsm.init();
vsm.start();
}
ViewStateMachine class (hpp):
class ViewStateMachine {
public:
ViewStateMachine(std::shared_ptr<QTTCPSocket> sock);
void init();
void start();
std::shared_ptr<QTTCPSocket> getSock();
private:
LoginView *_loginView;
std::shared_ptr<QTTCPSocket> _sock;
};
ViewStateMachine class (cpp):
#include "ViewStateMachine.hpp"
ViewStateMachine::ViewStateMachine(std::shared_ptr<QTTCPSocket> socket)
: _sock(std::move(socket))
{
}
void ViewStateMachine::init()
{
_loginView = new LoginView(this);
_loginView->init();
}
void ViewStateMachine::start()
{
_loginView->show();
}
std::shared_ptr<QTTCPSocket> ViewStateMachine::getSock()
{
_sock->send("test1"); // SIGSEGV inside (check above)
return _sock; // if I remove _sock->send("test1"), it SIGSEGV in the shared_ptr's constructor (only if called from a qt event (a button for example)
}
LoginView is a passive class, which register an event with QObject::connect(_connectBtn, SIGNAL(clicked()), this, SLOT(onClick_connectBtn())); with onClick_connectBtn() a member function of LoginView.
All these pieces of code might be confused so here a step-by-step explanation:
Start in main(): create a QTcpSocket * contained in a QTTCPSocket class contained in a std::shared_ptr<QTTCPSocket>.
Create a ViewStateMachine instance with the shared_ptr, which will be stored in the instance. We will call it vsm.
Call vsm.init() which will create a LoginView instance with this (vsm). LoginView will store the ViewStateMachine instance.
Call vsm.start() which will call _loginView.show() (from QT's QWidget), it will show the login view.
Everything works well and we can see the login view.
However, if I want to use my socket in the LoginView :
* when I want to use it from _loginView->init() or in the LoginView's constructor, it works well!
* when I want to use it from LoginView::onClick_connectBtn (called by QT, perhaps in a special environment like a constructor, not sure), it produces a SIGSEGV where I commented above in the code (shared_ptr's constructor or write function from the QT' socket).
To get the socket from LoginView, I use ViewStateMachine::getSock() (_viewStateMachine->getSock()).
Valgrind shows
pure virtual method called
terminate called without an active exception
The shared_ptr's constructor produces a SIGSEGV when it uses its mutex to increment the value.
The write SIGSEGV when I use _socket (QT' socket). The pointer address didn't change from beginning to end.
If there's any other question, please ask!
Thanks a lot for helping :).
EDIT: It works if I replace every std::shared_ptr with a C pointer.
Been beating my head against the wall for a while now, and am almost embarrassed to ask the community since it will most likely result in me getting schooled for a pointer or scoping .
I am using ROS to manipulate a robot that has two arms; each arm has a gripper. I have an arm class and a gripper class; the gripper is a member of the arm class. Relevant code posted below.
To sum up my code: the gripper class has members such as id which need to be initialized by the callback function. If these members are accessed before the callback is called, they will get bad data. Therefore, the class has an initialized_ variable and associated initialized() function, which simply checks to see if the callback has been called yet (initialized is set to false when constructed, then set to true in the callback). The design pattern for the arm class is similar; its initialize() function checks to see if the gripper is initialized. In the main function, in my ros loop, I check to make sure the arms are both initialized; if not, ros spins (aka calls the callbacks) until the callbacks initialize the grippers, allowing the program to continue.
To sum up my problem: the gripper's callback function is definitely being called, since "gripper initialized" is being printed. However, the properties it sets are not being retained, since "success!" is not being printed. Furthermore, an id of -1 is printed, a value set by the constructor rather than by the callback (an id of -1 is impossible).
Smells like a scoping or pointer issue, but I can't seem to find the problem. Since callback functions modify the "this" object, it is modifying the gripper itself, and that modification should remain after the function exits.
If anyone can offer help, it would be very greatly appreciated.
Thanks in advance.
class Gripper
{
private:
int id;
bool initialized_;
ros::Subscriber subscriber;
void callback(const baxter_core_msgs::EndEffectorState::ConstPtr& msg);
void init();
public:
Gripper();
Gripper(ros::NodeHandle handle);
bool initialized() { return this->initialized_; }
int get_id() { return this->id; }
};
// DEFAULT CONSTRUCTOR
Gripper::Gripper()
{
this->init();
...
}
// CONSTRUCTOR
Gripper::Gripper(ros::NodeHandle handle)
{
this->init();
this->subscriber = handle.subscribe(sub_topic, 10, &Gripper::callback, this);
...
}
// CALLBACK FUNCTION
// initializes gripper fields
void Gripper::callback(const baxter_core_msgs::EndEffectorState::ConstPtr& msg)
{
this->initialized_ = true;
this->id = msg->id;
...
if (this->initialized_) ROS_INFO("gripper initialized");
}
// INIT FUNCTION
// common code in constructors
// sets all bools to false, ints to -1
void Gripper::init()
{
this->initialized_ = false;
this->id = -1;
...
}
class Arm
{
public:
Gripper gripper;
Arm();
Arm(ros::NodeHandle handle);
bool initialized()
{
if (this->gripper.initialized()) ROS_INFO("success!");
ROS_INFO("gripper id: %d");
return this->gripper.initialized();
};
};
// DEFAULT CONSTRUCTOR
Arm::Arm()
{
this->gripper = gripper();
...
}
// CONSTRUCTOR
Arm::Arm(ros::NodeHandle handle)
{
this->gripper = gripper(handle);
...
}
int main(int argc, char **argv)
{
// initialize the node and create a node handle
ros::init(argc, argv, "master_node");
ros::NodeHandle nh;
ros::Rate loop_rate(10);
// make some variables for later
Arm left_arm(nh, LEFT);
Arm right_arm(nh, RIGHT);
// main program content
while (ros::ok())
{
// if everything is initialized, start doing the stuff
if (left_arm.initialized() && right_arm.initialized())
{
...
}
// spin & sleep
ROS_INFO("spin");
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
In order to use a COM object from a thread, I inserted CoInitialize(NULL) into the thread Execute function and CoUninitialize() into the Terminate function.
Everything works fine, except if the user aborts the thread by calling the Terminate function from the calling form.
It seems that the Terminate function called by a form is considered as another thread (Error message: 'The application called an interface that was marshalled for a different thread').
On the other hand I cannot put the code into a specific function to call by using Synchronize. This way makes the program still until the COM process of called function ends.
I know that functions to readdress the COM marshaling exist. But don't know exactly what to do. I did not find examples in C++, too.
Before asking help, I tried various ways to overcome the problem. Unfortunately I am here.
Here is my code:
class TThreadCamera : public TThread
{
private:
Variant Camera;
protected:
void __fastcall Execute();
public:
void __fastcall Terminate(TObject *Sender);
public:
__fastcall TThreadCamera();
};
-
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
}
//---------------------------------------------------------------------------
void __fastcall TThreadCamera::Execute()
{
FreeOnTerminate = true;
OnTerminate = &Terminate;
CoInitialize(NULL);
Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while ((! (bool) Camera.OlePropertyGet("ImageReady")))
Sleep 100;
}
//---------------------------------------------------------------------------
void __fastcall TThreadCamera::Terminate(TObject *Sender)
{
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
CoUninitialize();
}
//---------------------------------------------------------------------------
You need to call CoInitialize and CoUninitialize on the same thread, since they act on the calling thread. The OnTerminate event is always executed on the main thread.
So, remove your OnTerminate event handler, move that code into the thread, and so call CoUninitialize from the thread:
void __fastcall TThreadCamera::Execute()
{
FreeOnTerminate = true;
CoInitialize(NULL);
Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
// code to operate on the camera goes here
CoUninitialize();
}
It would probably be prudent to protect the uninitialization inside a finally block.
In Delphi, if you need to call a thread termination code in the thread context, you should override the protected TThread.DoTerminate method instead of writing OnTerminate event handler.
The TThread.OnTerminate event is called in the context of the main UI thread. The virtual TThread.DoSynchronize() method, which the worker thread calls after Execute() exits, uses TThread.Synchronize() to call OnTerminate. DoTerminate() is always called, even if Execute() exits due to an uncaught exception, so overriding DoTerminate() is a good way to perform thread-specific cleanup.
CoInitialize() and CoUninitialize() must be called in the same thread. So, you must call CoUninitialize() inside of Execute(), or override DoTerminate(). I prefer the latter, as it reduces the need for using try/catch or try/__finally blocks in Execute() (an RAII solution, such as TInitOle in utilscls.h, is even better).
An apartment-threaded COM object can only be accessed in the context of the thread that creates it. So you must call the camera's CameraStateproperty and AbortExposure() procedure inside of Execute(), or override DoTerminate(), as well.
The TThread.Terminate() method simply sets the TThread.Terminated property to true, it does nothing else. It is the responsibility of Execute() to check the Terminated property periodically and exit as soon as possible. Your while that waits for the camera's ImageReady property to be true can, and should, check the thread's Terminated property so it can stop waiting when requested.
Try something more like this:
class TThreadCamera : public TThread
{
private:
bool init;
protected:
void __fastcall Execute();
void __fastcall DoTerminate();
public:
__fastcall TThreadCamera();
};
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
FreeOnTerminate = true;
}
void __fastcall TThreadCamera::Execute()
{
init = SUCCEEDED(CoInitialize(NULL));
if (!init) return;
Variant Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while (!Terminated)
{
if ((bool) Camera.OlePropertyGet("ImageReady"))
return;
Sleep(100);
}
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
}
void __fastcall TThreadCamera::DoTerminate()
{
if (init) CoUninitialize();
TThread::DoTerminated();
}
Or:
class TThreadCamera : public TThread
{
protected:
void __fastcall Execute();
public:
__fastcall TThreadCamera();
};
#include <utilcls.h>
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
FreeOnTerminate = true;
}
void __fastcall TThreadCamera::Execute()
{
TInitOle oleInit;
Variant Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while (!Terminated)
{
if ((bool) Camera.OlePropertyGet("ImageReady"))
return;
Sleep(100);
}
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
}
I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.
I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum
My Qt application has a Qt gui (basically some buttons and an opengl context which draws data). I've also added scriptability exploiting PythonQt classes. The commands are evaluated from inside a PythonQtScriptingConsole.
I've explicitly created wrapper classes and factory methods to send C++ calls via the current python context through the console, but when running long tasks from inside the console, the gui freezes because (I think) the event loop is not processed. So a first solution would be to process the event loop with a timer, but this is both slow and kinda stupid I think, so I don't like it. A
Has someone some hint? Is the Python Global Interpreter Lock a problem here?
Yes, the GUI is freezing because the long call into Python is being executed via the UI thread. To get around this, I was able to subclass QThread and issue commands into the Python module via a Command pattern.
Before you start making calls into multiple Python modules using the following classes, be sure to initialize thread support in Python by calling PyEval_InitThreads() as you'll see in my main() function.
Good luck!
int main( int argc, char **argv ) {
QApplication qapp(argc, argv);
PyEval_InitThreads(); // IMPORTANT
PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
PythonQtObjectPtr module = PythonQt::self()->createUniqueModule();
ThreadedPythonContext context(module);
context.start();
# issue some commands into the module
context.issue("import sys");
context.issue("sys.path.append('C:\\Python27\\Lib\\site-packages')");
context.issue("import time");
context.issue("last = time.localtime().tm_sec");
// Release the global interpreter lock (if it has been created and thread support
// is enabled) and reset the thread state to NULL, returning the previous thread
// state (which is not NULL). If the lock has been created, the current thread must
// have acquired it. (This function is available even when thread support is
// disabled at compile time.)
// give up control of the GIL
PyThreadState *state = PyEval_SaveThread();
return qapp.exec()
}
ThreadedPythonContext.h
#ifndef THREADEDPYTHONCONTEXT_H
#define THREADEDPYTHONCONTEXT_H
#include "PythonQt.h"
#include <QtCore/QMutexLocker>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>
class ThreadedPythonContext : public QThread
{
Q_OBJECT
public:
ThreadedPythonContext(const PythonQtObjectPtr &context) :
QThread(),
_context(context),
_running(true)
{
}
~ThreadedPythonContext() {
_running = false;
wait();
}
void issue(const QString &code) {
_lock.lock();
_commands.enqueue(code);
_lock.unlock();
_CommandQueued.wakeOne();
}
bool isCommandQueueEmpty() {
QMutexLocker lock(&_lock);
return _commands.isEmpty();
}
protected:
QString dequeue() {
QMutexLocker lock(&_lock);
QString cmd( _commands.dequeue() );
return cmd.isEmpty() ? "\n" : cmd;
}
void run() {
QMutex signal;
PyGILState_STATE state;
while(_running) {
// wait to be signaled ...
signal.lock();
_CommandQueued.wait(&signal,1);
signal.unlock();
if ( isCommandQueueEmpty() ) {
continue;
}
while ( !isCommandQueueEmpty() ) {
PythonQtObjectPtr p;
PyObject* dict = NULL;
state = PyGILState_Ensure();
if (PyModule_Check(_context)) {
dict = PyModule_GetDict(_context);
} else if (PyDict_Check(_context)) {
dict = _context;
}
if (dict) {
// this command blocks until the code has completed execution
emit python_busy(true);
p.setNewRef(PyRun_String(dequeue().toLatin1().data(), Py_single_input, dict, dict));
emit python_busy(false);
}
// error in the kernel
if (!p) {
PythonQt::self()->handleError();
}
PyGILState_Release(state);
}
}
}
PythonQtObjectPtr _context;
QMutex _lock;
QQueue<QString> _commands;
QWaitCondition _CommandQueued;
bool _running;
signals:
void python_busy(bool);
};
#endif //THREADEDPYTHONCONTEXT_H