4

To improve code readability, I want to create an object inside a function an return it by value (I let the compiler the task of optimizing the memory).

If I have a regular class I can do the following:

MyClass myFunction01()
{
  MyClass theRegularObject;
  //do things
  return theRegularObject;
}

So in my code I can do:

MyClass myObject = myFunction01();

However, if MyClass is a QObject derived one (let's call it QObjDerivedClass), I get a compilation error:

QObjDerivedClass::QObjDerivedClass(const QObjDerivedClass &) : attempting to reference a deleted function.

I think that the problem resides in that the QObject has neither a copy constructor nor an assignment operator QObject Doc.

As possible solutions I think the following ones, but maybe I am missing a better one?

1.Create the object in main and pass the object as a reference to the function

void myFunction01(CMyClass &theObj) {//do things}

//In my program
CMyClass myObj;
myFunction01(myObj);

2.Create a dynamic object inside the function and return a pointer (a smart pointer?)

QSharedPointer<CMyClass> myFunction01()
{
  QSharedPointer<CMyClass> p_theObj(new CMyClass);            
  //do things
  return p_theObj;
}

//At my program
QSharedPointer<CMyClass> p_myObj = myFunction01();

//When p_myObj goes out of scope the CMyClass object will be deleted.
//WARNING: Very important not to set a parent when we create the CMyClass object. 
//Otherwise, we will have problems due to double deletion.

Are there any better/other ideas?

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
pablo_worker
  • 1,042
  • 9
  • 26
  • Or just use a plain pointer. This is what Qt usually does to `QObject`s. Please also check this: http://doc.qt.io/qt-5/objecttrees.html – Kane Mar 10 '17 at 15:10
  • 1
    You cannot return a polymorphic object by value, because you get object slicing. I'm sure that's why QObject doesn't have a copy constructor or assignment operator, to prevent you from trying something that won't work. – Mark Ransom Mar 10 '17 at 15:27
  • @MarkRansom, not really. `QObject` is neither copyable nor movable because other `QObject`s refer it via its address, e.g. in parent-child relationship or in signals and slots. Check out this: https://bugreports.qt.io/browse/QTBUG-49604 – Kane Mar 10 '17 at 15:39
  • It's possible to implement move semantics for custom `QObject` subclasses that aren't widgets, with the natural limitation that none of your code can hold on to the object via a naked pointer as such a pointer would become invalid. `QPointer` would still work, of course. But since Qt itself only references `QObject`s internally in a few well known locations that the move constructor can fix up, it's possible to do it without patching Qt. I'll probably write up the solution I use at some point. It does the job. `QWidget` is too convoluted to become a movable class without changing Qt itself. – Kuba hasn't forgotten Monica Mar 10 '17 at 17:35
  • Also note that double deletion isn't a given. All you have to pay attention to is the guaranteed scoped object destruction order. It's in the C++ standard, so you can depend on it - lots of code would break if it didn't work :) – Kuba hasn't forgotten Monica Mar 10 '17 at 17:38

1 Answers1

4

By design, a QObject should never be passed by value.

The Qt Object Model requires that we think of Qt Objects as identities, not values. Values are copied or assigned; identities are cloned ... Therefore, QObject and all subclasses of QObject (direct or indirect) have their copy constructor and assignment operator disabled. (Source)

Because of this, your original example is inherently wrong. Instead you should be interacting with QObjects (and QObject derived classes) with pointers.

The standard practice with Qt is to allocate your objects on the heap using new. As long as the object has a proper parent, it will be destroyed automatically.

All child objects are deleted. If any of these objects are on the stack or global, sooner or later your program will crash. (Source)

This practice can be seen in official samples, such as this. The objects are explicitly allocated on the heap, and clean-up (delete) is left for the parent to handle.

So to summarize: Allocate your QObject-derived objects on the heap and pass them by pointers.

Note: If you would rather make use of a smart-pointer, this answer has a good summary of those built into Qt.

Community
  • 1
  • 1
ssell
  • 6,429
  • 2
  • 34
  • 49
  • Thank you for your response. I was hoping not to use child-parent relationship for this case so I will use the smart-pointer approach. – pablo_worker Mar 11 '17 at 10:51