Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you deal with memory management and signal/slots?

I have an object which emits a signal with an object:

MyObj *obj = this->generateObj();
emit newObjSignal(obj);
delete obj;

and I have one or more people who connect to this. The problem is that the delete call gets called before the objects receive the signal. How do I deal with this?

like image 690
chacham15 Avatar asked Dec 21 '22 08:12

chacham15


2 Answers

Use smart pointers, so that memory management will be handled automatically and you will be sure you will have:

  1. No dangling pointers;
  2. No memory leaks.

In this case, it seems to me std::shared_ptr<> (or std::tr1::shared_ptr<> or boost::shared_ptr<> if you are not working with C++11) is the correct choice:

#include <memory> // For std::shared_ptr<>
// ...
std::shared_ptr<MyObj> obj(this->generateObj());
emit_new_signal(obj);
// delete obj; // <== No need for this anymore!

Also notice, that the handler functions will have to accept a std::shared_ptr<MyObj> rather than a raw pointer MyObj*, but the code inside those handlers won't have to be changed, because std::shared_ptr provides an overload of operator ->.

Notice that, in general, the use of new is discouraged in C++11, and when possible one should use std::make_shared<> to create shared_ptrs. Thererfore, you may want to rewrite your generateObj() member function so that it returns an std::shared_ptr<MyObj> instead of a MyObj*, and let it use std::make_shared<MyObj>() internally to instantiate the object.

NOTE:

As pointed out by Geier in the comments, Qt has its own smart pointer class QSharedPointer that you may want to use.

like image 74
Andy Prowl Avatar answered Dec 24 '22 00:12

Andy Prowl


While you can use a QSharedPointer, another approach is to not use dynamic memory allocation. The code would therefore be -

MyObj obj = this->generateObj();
emit newObjSignal(obj);

This will obviously result in copies of MyObj being created. Qt generally solves this issue by using implicit sharing or copy-on-write.

In order for your own class to use this implicit sharing mechanism you will have to change the structure of your class and use QSharedData and QSharedDataPointer

class MyObjData : public QSharedData {
public:
    int variable;
};

class MyObj {
    MyObj() : d(new MyObjData) {}
    int foo() { return d->variable; }
private:
    QSharedDataPointer<MyObjData> d;
};

This way copies of MyObj would be very cheap and you can easily pass it over a signal.

This is IMO a lot cleaner than using a QSharedPointer.

like image 38
Vishesh Handa Avatar answered Dec 24 '22 01:12

Vishesh Handa