Qt deletion pointer method - c++

In a Qt project I have a method
void ProtocolHandler::interpretData(uint8_t packet_id){
PacketClass *packet = new RSP2StatusPacket(_packet_buf);
emit packetReceived(packet);
}
where I declare an object packet of type PacketClass and then I emit the signal
packetReceived (PacketClass*)
In another class I have the following slot:
void ReceiverCommands::processReceivedPacket(PacketClass* pkt)
{
status_packet *payload = pkt->getPayload();
delete pkt
}
Is it correct to delete the newer PacketClass *packet in the slot method?
Sometimes my program crashes so what is the best method to delete a pointer passed in a signal/slot (I suppose I must delete the pkt because I instantiate a new packet in "interpretData" method).

There can be an arbitrary number of slots attached to a signal (including zero and more than one!), so you should never expect a slot to deallocate memory passed via a naked pointer.
You should be passing a QSharedPointer<PacketClass> and use it. It will do the deletion as and when needed.
typedef QSharedPointer<PacketClass> PacketClassPtr;
Q_DECLARE_METATYPE(PacketClassPtr)
ProtocolHandler {
...
Q_SIGNAL void packetReceived(PacketClassPtr packet);
}
void ProtocolHandler::interpretData(uint8_t packet_id){
PacketClassPtr packet(new RSP2StatusPacket(_packet_buf));
emit packetReceived(packet);
}
void ReceiverCommands::processReceivedPacket(PacketClassPtr pkt)
{
status_packet *payload = pkt->getPayload();
}

Assuming PacketClass is derived from QObject, then call the deleteLater function: -
pkt->deleteLater();
This will handle deleting the object at the right time, after it has been through handling signals and slots and when control is returned to the event loop.
See the documentation for deleteLater here, which is also relevant for Qt4

Related

QLabel not updating image content [duplicate]

I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue

Smart pointers as an alternative to QObject::deleteLater()

So I have got a function which makes a network request:
void MyClass::makeRequest()
{
ApiRequest* apiRequest = new ApiRequest();
apiRequest->makeRequest();
connect(apiRequest, &ApiRequest::requestFinished, this, &MyClass:onApiRequestFinished);
}
Since I need the object apiRequest to survive until my request is finished I then call:
void MyClass:onApiRequestFinished()
{
// do my stuff
// now I can delete my request object ((retrieved using sender()) using deleteLater()
}
Now since I am not using Qt parent-child system in this case how can I manage the memory using C++11 smart pointers instead of calling deleteLater()?
I don't think you can solve this with C++ smart pointers without storing the apiRequest object in some container until requestFinished is triggered.
Maybe an alternative would be to create an ApiRequest::finished() method to use as the receiver of the signal, then pass this to ApiRequest's constructor so finished() can call MyClass::onApiRequestFinished(), and then have finished() call delete this after onApiRequestFinished() exits, eg:
void MyClass::makeRequest()
{
ApiRequest* apiRequest = new ApiRequest(this);
apiRequest->makeRequest();
}
void MyClass::onApiRequestFinished()
{
// do my stuff
}
...
ApiRequest::ApiRequest(MyClass *cls)
: m_cls(cls)
{
connect(this, &ApiRequest::requestFinished, this, &ApiRequest::finished);
}
void ApiRequest::finished()
{
m_cls->onApiRequestFinished();
delete this;
}
Not sure how feasible this is with Qt, but maybe worth a try.

Find the sender of the `destroyed (QObject*)` signal

I am currently wondering how to reasonably use the QObject::destroyed(QObject*) signal.
An observation
I noticed that QWidget-derived objects are treated slightly different. Consider the following small self-contained and compiling example:
/* sscce.pro:
QT += core gui widgets
CONFIG += c++11
TARGET = sscce
TEMPLATE = app
SOURCES += main.cpp
*/
#include <QApplication>
#include <QPushButton>
#include <QTimer>
#include <QtDebug>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::destroyed,
[=](QObject *o) { qDebug() << o; });
delete button;
QTimer *timer = new QTimer;
QObject::connect(timer, &QTimer::destroyed,
[=](QObject *o) { qDebug() << o; });
delete timer;
return app.exec();
}
This is its output:
QWidget(0x1e9e1e0)
QObject(0x1e5c530)
So presumably, the signal is emitted from QObject's d-tor, so only the QObject base remains when the slot is called for the QTimer. However, QWidget's d-tor seems to intercept as it still identifies itself as a QWidget from the slot.
And the problem
Let's assume we have a timer pool that organizes a couple of timers in a QList<QTimer *>:
struct Pool {
QTimer *getTimer() {
return timers.at(/* some clever logic here */);
}
QList<QTimer *> timers;
};
Now an incautious user might delete the timer that was borrowed to him/her. Well, we can react, and simply remove that timer from the list. A slot will do the trick:
Pool::Pool() {
/* for each timer created */
connect(theTimer, SIGNAL(destroyed(QObject*),
this, SLOT(timerDestroyed(QObject*));
}
void Pool::timerDeleted(QObject *object) {
QTimer *theTimer = /* hrm. */
timers.removeOne(theTimer);
}
But what now? Hrm. When the slot is called, the QTimer already is in destruction and partially destroyed - only its QObject base remains. So I objously cannot qobject_cast<QTimer *>(object).
To resolve this issue, I could think of the following tricks:
Store QObjects in the list. Then I'd have to downcast every time I use an item from the list. This could be done using static_cast, though, as I know there will only be QTimers in the list, so no need for dynamic_cast or qobject_cast.
Insteat of removeOne traverse the list using an iterator and then compare each QTimer item directly to the QObject. Then use QList::erase or such.
static_cast or even reinterpret_cast the QObject to a Qtimer nonetheless.
What should I do?
If you're looking for tricks, you could simply use the base QObject objectName and remove the destroyed timer based on that.
It seems clear that your problem is one of object ownership; in particular, how to convey who is responsible for destroying an object. If your Pool object owns the QTimer objects (and thus the user should not delete them), make it clear through the interface, for example returning a QTimer& instead of a QTimer* from your getTimer method. I'm not really well versed in Qt, but if you actually wanted to transmit ownership of the object returned from a method and thus make the user responsible of its deletion, you'd likely return a std::unique_ptr<QTimer>.
Just do a direct cast:
void Pool::timerDeleted(QObject *object) {
QTimer *theTimer = (QTimer*)object; //qobject_cast doesn't work here
//we are sure that only a timer can be a sender
timers.removeOne(theTimer);
}
You could base your list on QPointer instead of raw pointers. I.e. write
QList<QPointer<QTimer>> timers;
Now when one of the timers in the list goes away, the corresponding entry in the list will automagically be cleared. It will not be removed, though! But when you access the timer via your getTimer() method, an entry whose timer has been deleted will now return a nullptr (and not a dangling pointer).
And yes, QWidget emits destroyed() in its own destructor. This is why you see a real QWidget in that case. Everybody else uses QObject's implementation.
The other way around is safe. Cast QTimer * to QObject * instead:
void Pool::timerDeleted(QObject *object) {
const auto it = std::find_if(timers.begin(), timers.end(), [object](QTimer *timer) {
return static_cast<QObject *>(timer) == object;
});
Q_ASSERT(it != timers.end());
timers.erase(it);
}
Or use erase_if(QList &list, Predicate pred) introduced in Qt 6.1.

QT slots and signals fail

Hi there i got problem with signal and slots in qt.
In main i have created object of mainwindow.
in mainwindow.cpp i creating object of another class(modbus_tcp).
i also creating connection here
void MainWindow::on_ConnectB_clicked()
{
modbus_tcp appts;
appts.slave();
connect(&appts,SIGNAL(msgSended(QString)),this,SLOT(msgEdit(QString)));
}
between slot declared in mainwindow.cpp/h
public slots:
void msgEdit(QString m);
void MainWindow::msgEdit(QString m)
{
ui->sendEdit->setText(m);
ui->recvEdit->setText(m);
//QMessageBox::information(0,"bad", "nope nope nope");
}
and signal declared in modbus_tcp.h
signals:
void msgSended(QString);
next i emiting signal in modbus_tcp.cpp
emit msgSended("asdasd");
and nothing happen
when i trying to emit in mainwindow.cpp its working
any ideas ?
void MainWindow::on_ConnectB_clicked()
{
modbus_tcp appts;
appts.slave();
connect(&appts,SIGNAL(msgSended(QString)),this,SLOT(msgEdit(QString)));
}
appts was created in stack, so it will be deleted at the end of slot execution. Try to create it in the heap(try to use pointer).
void MainWindow::on_ConnectB_clicked()
{
modbus_tcp *appts = new modbus_tcp;
connect(appts,SIGNAL(msgSended(QString)),this,SLOT(msgEdit(QString)));//first!
appts->slave();//now you can call it
}
Use pointers, but first of all connect, and after this call slave. You emit signal in slave, but there is no connection in this time. You should do connection firstly and after that, you will be able to catch signals.

Updating pointer using signals and slots

I am very new to Qt; please help me to solve the problem.
I am using a thread to perform intensive operations in the background. Meanwhile I want to update the UI, so I am using SIGNALS and SLOTS. To update UI I emit a signal and update UI.
Let us consider below sample code,
struct sample
{
QString name;
QString address;
};
void Update(sample *);
void sampleFunction()
{
sample a;
a.name = "Sachin Tendulkar";
a.address = "India"
emit Update(&a);
}
In the above code we are creating a local object and passing the address of a local object. In the Qt document, it says that when we emit a signal it will be placed in the queue and late it will be delivered to the windows. Since my object is in local scope it will be delete once it goes out of the scope.
Is there a way to send a pointer in a signal?
You're insisting on doing the wrong thing, why? Just send the Sample itself:
void Update(sample);
//...
sample a("MSalters", "the Netherlands");
emit Update(a);
Unless you've determined that this code is a performance bottleneck you would be better to just pass a copy of the object rather than a pointer.
Really, I mean it.
However, if you must use pointers then use a boost::shared_ptr and it will delete itself.
void Update(boost::shared_ptr<sample> s);
void sampleFunction()
{
boost::shared_ptr<sample> a = boost::shared_ptr<sample>(new sample());
a->name = "Sachin Tendulkar";
a->address = "India"
emit Update(a);
}