Smart pointers as an alternative to QObject::deleteLater() - c++

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.

Related

QTimer::SingleShot fired after object is deleted

// Example class
class A : public QObject
{
Q_OBJECT
void fun() {
Timer::SingleShot(10, timerSlot); //rough code
}
public slot:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a deleted
In this case after a is deleted and timer is fired, would it execute timerSlot()? I'm getting an extremely rare crash and not sure if it's because of something fishy in this logic.
Even if the timer fires, it won't trigger the slot. The docs of ~QObject state: All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. The only way you can trigger the A::timerSlot and delete A at the same time is if you use threads.
You are not obligated to disconnect an object's signals and slots before deleting it.
The QObject destructor will clean up obsolete signal-slot connection for you, as long as you:
Inherit from QObject
Use the Q_OBJECT macro in your class definition
Following these conventions ensures that your object emits a destroyed() signal when deleted. That's actually what Qt's signals-and-slots system uses to clean up dangling references.
You can listen to the destroyed() signal yourself if you'd like to add some debugging code to track object lifecycles.
(Depending on the particular version of Qt/moc you are using, it's quite possible that code with a non-QObject using slots, or a QObject-derived class that doesn't have Q_OBJECT in its header will still compile but cause the timerSlot() method to be invoked on a garbage pointer at runtime.)
I'm getting a extremely rare crash due to timer out of object scope which I need to fire just once. I use QTimer::singleShot which is static method and does not pertain to an instance of QTimer object which I would release with the context it fires the signal to.
That is of course solved in QTimer class and desired behavior controlled by the instance of timer class with non-static QTimer::singleShot property set to true.
// declaration
QScopedPointer<QTimer> m_timer;
protected slots:
void onTimeout();
// usage
m_timer.reset(new QTimer);
m_timer->setSingleShot(true);
QObject::connect(m_timer.data(), SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer->start(requiredTimeout);
So, no crash should happen due to timer released with the context object.
Edit: This answer was in response to the original question which did not use QObject but had class A as a standalone class inheriting nothing. The question was later edited making this answer obsolete, but I'll leave it here to show what would be needed if not using QObject.
The only way you can do that is if you keep the object alive until the timer has fired. For example:
class A : enable_shared_from_this<A> {
void fun() {
QTimer::singleShot(10, bind(&A::timerSlot, shared_from_this()));
}
public:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a goes out of scope, but its referent is kept alive by the `QTimer`.
The reason the above works is that you capture a shared_ptr to class A when setting the timer, and the timer will hold onto it (else it can't fire).
If you don't like or can't use recent C++ features or Boost:
struct Functor {
Functor(SharedPointer<A> a) : _a(a) {}
void operator() { a->timerSlot(); }
SharedPointer _a;
};
class A {
void fun(shared_ptr<A> self) {
QTimer::singleShot(10, Functor(self));
}
public:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun(a);
To reach certainty, you can stop the timer yourself:
class A : public QObject {
QTimer t;
A() { connect(Signal-Slots); }
~A() { t.stop(); }
fun() { t.start(10); }
...
};

Qt deletion pointer method

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

How to make a function to be a slot temporally in Qt?

To make a function of a class to be a slot, the class has to inherit from QObject. However, QObject takes up a quite large amount of memory. I am not sure how much it is and if the memory is for each class or each object. My code has many small data whose functions can be a slot sometime. I am wonder if there is a way to make a function of class to be a slot temporally when using it. After using it, the memory for the slot cost will be deleted. The following code illustrates the requirement.
class SmallData // size of 2 or 3 integers.
{
public:
virtual void F(); // use it as a slot.
virtual QMenu* createMenu(); // use this to create the context menu with
// an action connected to F()
...
};
// use the small data
vector<SmallData> vec(1000000); // the vector is put at a tree view. When an
// item in the tree view is selected, a context
// menu pop up with an action to run F().
SmallData* data = treeView.selectedItem();
connect(action, SIGNAL(triggered()), data, SLOT(F())); // How to make F() to be
// a slot just here.
// The action is from
// data->createMenu().
If you can use Qt5, you can connect signals to plain functions and static methods (which essentially are funnily named plain functions):
connect(action, &QAction::triggered,
&SmallData::statF);
Where action is a QAction instance, and SmallData::statF is a static method of SmallData.
Edit per Christian Rau's comment, to call a particular instance, you can also connect to lambda:
connect(action, &QAction::triggered,
[data]() { data->F(); });
Already with Qt4, you can use QSignalMapper to achieve much the same effect, with a few more objects. It allows you to add add a parameter (in this case, probably an integer index to your vec) to signal, based on which object emitted it. But in Qt4, receiver must still always be a QObject.
For using the signal slot mechanism, you won't get around QObject, but what you can do is create a temporary object that has a slot calling your function. You just have to care for properly releasing the object. Something like:
class Callback : public QObject
{
Q_OBJECT
public:
typedef std::function<void()> FunctionType;
Callback(FunctionType fn, bool oneShot = true, QObject *parent = nullptr)
: QObject(parent), fn_(std::move(fn)), oneShot_(oneShot) {}
public slots:
void call()
{
fn_(); //delegate to callback
if(oneShot_)
deleteLater(); //not needed anymore
}
private:
FunctionType fn_;
bool oneShot_;
};
Callback* makeCallback(FunctionType fn, bool oneShot = true, QObject *parent = nullptr)
{
return new Callback(std::move(fn), oneShot, parent);
}
You then just create a (more or less temporary) Callback object each time needed:
SmallData* data = treeView.selectedItem();
connect(action, SIGNAL(triggered()),
makeCallback(std::bind(&SmallData::F, data)), SLOT(call()));
With the oneShot parameter you can control if the slot should dissolve automatically once triggered.
The only problem is, if this slot is never called, you have a leaking Callback hanging around. To accomodate this, you can pass something meaningful into the parent argument, so that Qt cares for proper deletion at least at some later point in time:
SmallData* data = treeView.selectedItem();
connect(action, SIGNAL(triggered()),
makeCallback(std::bind(&SmallData::F, data), true, this), SLOT(call()));
This way you can also bind the lifetime of the callback object (and thus the signal-slot connection) to some other object (e.g. the action itself and deleting the action when no item is selected, or something the like).
Alternatively, you can also remember the Callback object for the currently selected item and care for proper deletion yourself, once it's delesected.
disclaimer: Beware that the above example contains plenty of C++11, but I'm not in the mood to rewrite this for C++03. Likewise can this solution be imporved further, maybe using a templated functor instead of a std::function (but if I remember correctly the Qt meta object system doesn't like templates that much).
EDIT: In the end the solution proposed by Frank Osterfeld in his comment might be a much simpler approach for your situation than my overly generic object lifetime madness above: Just connect the action to a single slot of a higher level object (your main widget or maybe the item model containing the data vector) and call F on the currently selected item:
connect(action, SIGNAL(triggered()), this, SLOT(callF()));
...
void MyController::callF()
{
treeView.selectedItem()->F();
}
I don't think that what you try to do is possible in Qt.
If you really don't want to inherit QObject, then I suggest you have a look at the boost signals and slots mechanism.

Prevent Firing Signals in Qt

We have a QCheckBox object, when user checks it or removes check we want to call a function so we connect our function to stateChanged ( int state ) signal. On the other hand, according to some condition we also change the state of QCheckBox object inside code, and this causes the unwanted signal.
Is there any way to prevent firing signal under some conditions?
You can use the clicked signal because it is only emitted when the user actually clicked the check box, not when you manually check it using setChecked.
If you just don't want the signal to be emitted at one specific time, you can use QObject::blockSignals like this:
bool oldState = checkBox->blockSignals(true);
checkBox->setChecked(true);
checkBox->blockSignals(oldState);
The downside of this approach is that all signals will be blocked. But I guess that doesn't really matter in case of a QCheckBox.
You can always block signal emission on QObjects using QObject::blockSignals(). Note that to be correct about things, you should remember the old state (returned from the function call), and restore it when you are done.
At my job, we prefer RAII for this sort of thing. A simple class to do so might look like this:
class SignalBlocker
{
public:
SignalBlocker( QObject *obj ) : m_obj( obj ), m_old( obj->blockSignals( true ) )
{
}
~SignalBlocker()
{
m_obj->blockSignals( m_old );
}
private:
QObject *m_obj;
bool m_old;
};
Edit: Starting with Qt 5.3, see QSignalBlocker (h/t to HappyCactus in comments)
While learning Qt, I ran into this problem with a set of interconnected widgets that I wanted to update "atomically". I liked #cjhuitt's solution, but found that it goes even better with a bit of syntactic sugar based on proxy objects. Here's the approach that I used...
First, I defined a class template for a blocker proxy object. Like Caleb's, this blocks the signals on construction, and then restores their previous state on destruction. However, it also overloads the -> operator to return a pointer to the blocked object:
template<class T> class Blocker {
T *blocked;
bool previous;
public:
Blocker(T *blocked)
: blocked(blocked),
previous(blocked->blockSignals(true)) {}
~Blocker() { blocked->blockSignals(previous); }
T *operator->() { return blocked; }
};
Next, I defined a small template function to construct and return a Blocker:
template<class T> inline Blocker<T> whileBlocking(T *blocked) {
return Blocker<T>(blocked);
}
Putting this all together, I'd use it like this:
whileBlocking(checkBox)->setChecked(true);
or
whileBlocking(xyzzySpin)->setValue(50);
This gets me all the benefits of RAII, with automatically paired blocking and restore around the method call, but I don't need to name any wrapper or state flags. It's nice, easy, and pretty darn foolproof.
You can QObject::disconnect to remove the corresponding signal-slot connection and can QObject::connect again once you are done...
In QObject derived classes, you can call blockSignals(bool) to prevent the object from emitting signals. So for example:
void customChangeState(bool checked)
{
blockSignals(true);
ui->checkBox->setCheckState(Qt::Checked);
// other work
blockSignals(false);
}
The above method would change the check state without clicked, stateChanged, or any other signals being emitted.
Qt5.3 introduced the QSignalBlocker class that does exactly what needed in an exception safe way.
if (something) {
const QSignalBlocker blocker(someQObject);
// no signals here
}
Even in QT5, its a bit cumbersome when there are many/several things to block. Here's a multi-object version that is concise to use:
class SignalBlocker
{
public:
SignalBlocker(QObject *obj)
{
insert( QList<QObject*>()<<obj );
}
SignalBlocker(QList<QObject*> objects)
{
insert(objects);
}
void insert(QList<QObject*> objects)
{
for (auto obj : objects)
m_objs.insert(obj, obj->signalsBlocked());
blockAll();
}
void blockAll() {
for( auto m_obj : m_objs.keys() )
m_obj->blockSignals(true);
}
~SignalBlocker()
{
for( auto m_obj : m_objs.keys() )
m_obj->blockSignals( m_objs[m_obj] );
}
private:
QMap<QObject*,bool> m_objs;
};
usage:
void SomeType::myFunction()
{
SignalBlocker tmp( QList<QObject*>()
<< m_paramWidget->radioButton_View0
<< m_paramWidget->radioButton_View1
<< m_paramWidget->radioButton_View2
);
// Do more work, ...
}
When some UI element should not respond to user it is appropriate to disable it. So that user would know that this element is not accepting input.

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);
}