std::unique_ptr with QObject derived class?
-
Hi,
My MainWindow class holds two instances of a class I created that for a time were defined in its header like so:
mainwindow.h:
class MainWindow : public QMainWindow { Q_OBJECT // Required for classes that use Qt elements //... MyClass mMyClassOne; MyClass mMyClassTwo; //...
and at some point during the user's use of the MainWindow, instances of this class are constructed and assigned to these member variables like so:
mainwindow.cpp:
void MainWindow::updateSourceDirectory() { //... mMyClassOne = MyClass(var1, var2); //...
this function can be called multiple times to effectively reset set some parameters each time, including this instance of MyClass, which works correctly here as when the function runs again the old instance is abandoned and a new one is constructed and assigned to the MainWindow member variable. Since these variables are allocated on the stack this is all fine.
Eventually, it came to be that this class now has several instance member functions that perform process intensive operations. I have a QProgressBar widget in my MainWindow that I want updated several times to show the progress of these operations, but I don't want to have ugly code that passes around a pointer to the progress bar into the MyClass instance (poor modulaization since MyClass would then depend on the implementation of MainWindow). So, I decided to make use of signals/slots and turn MyClass into a QObject derived class:
MyClass.h:
class MyClass: public QObject { Q_OBJECT // Required for classes that use Qt elements //... signals: void processSegmentCompleted(double progressPercent);
Because QObjects and their derived classes explicitly forbid copying via a deleted copy operator, this statement became an issue:
mMyClassOne = MyClass(var1, var2);
Ok, no problem, I simply switched to using pointers -
mainwindow.h: class MainWindow : public QMainWindow { Q_OBJECT // Required for classes that use Qt elements //... MyClass *mMyClassOnePtr; MyClass *mMyClassTwoPtr; //...
mainwindow.cpp:
void MainWindow::updateSourceDirectory() { //... if(mMyClassOnePtr != NULL) delete mMyClassOnePtr; mMyClassOnePtr = new MyClass(var1, var2, this); // Gave MyClass a "parent" parameter since it now derives from QObject //...
This complies fine; however, I realized that I only ever want to have one pointer for each of these instances and absolutely want the old instance deleted before the pointer is reassigned to a new instance every time this function is called. Therefore, I figured I should use std::unique_ptr:
mainwindow.h:
class MainWindow : public QMainWindow { Q_OBJECT // Required for classes that use Qt elements //... std::unique_ptr<MyClass> mMyClassOnePtr; std::unique_ptr<MyClass> mMyClassTwoPtr; //...
mainwindow.cpp:
void MainWindow::updateSourceDirectory() { //... mMyClassOnePtr = std::make_unique<MyClass>(MyClass(var1, var2, this)); // Line 135 (see errors) //...
This would be great, but unfortunately gives me compilation errors that I don't fully understand. They seem to be suggesting that "make_unique" is trying to use the copy operator for MyClass (which is deleted since its derived from QObject), which has me confused since I thought the entire point of std:unique_ptr was that its reference cannot be copied.
Here are the errors (CoHMod == MyClass):
C:\Engineering\Development\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include\memory:2539: error: C2280: 'CoHMod::CoHMod(const CoHMod &)': attempting to reference a deleted function C:\Users\Chris\Engineering\Development\Qt\Qt 5.12\CoH_Mod_Patch_Generator\cohmod.h:142: compiler has generated 'CoHMod::CoHMod' here C:\Users\Chris\Engineering\Development\Qt\Qt 5.12\CoH_Mod_Patch_Generator\cohmod.h:142: 'CoHMod::CoHMod(const CoHMod &)': function was implicitly deleted because a base class invokes a deleted or inaccessible function 'QObject::QObject(const QObject &)' C:\Engineering\Development\Qt\5.12.1\msvc2017_64\include\QtCore\qobject.h:449: 'QObject::QObject(const QObject &)': function was explicitly deleted C:\Users\Chris\Engineering\Development\Qt\Qt 5.12\CoH_Mod_Patch_Generator\mainwindow.cpp:135: see reference to function template instantiation 'std::unique_ptr<CoHMod,std::default_delete<_Ty>> std::make_unique<CoHMod,CoHMod,0>(CoHMod &&)' being compiled with [ _Ty=CoHMod ]
The template its referring to at line 2539 in "memory" is:
/template<class _Ty, class... _Types, enable_if_t<!is_array_v<_Ty>, int> = 0> _NODISCARD inline unique_ptr<_Ty> make_unique(_Types&&... _Args) { // make a unique_ptr return (unique_ptr<_Ty>(new _Ty(_STD forward<_Types>(_Args)...))); }
Line 142 of (myclass.h) cohmod.h is the end of the class declaration, and line 135 of mainwindow.cpp as refered to by the last error is the line in which I'm trying to use "make_unique" to assign an instance of MyClass to mMyClassOnePtr.
I tried Googling "std::unique_ptr" with QObject but couldn't find much and kept running into posts where people seemed to be using it with QObjects just fine and their posts were about other issues.
I can post more code but it is a tad long so I'd rather wait for specific pieces of it to be requested rather than just posting it all
Any suggestions?
Thanks.
-
@oblivioncth said in std::unique_ptr with QObject derived class?:
mMyClassOnePtr = std::make_unique<MyClass>(MyClass(var1, var2, this));
This is wrong, see https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
You're basically trying to create an instance of MyClass and passing this to the ctor of MyClass with the statement above. -
Ah, facepalms.
It had been a bit since I looked at the documentation for make_unique when I actually tried implementing it and swore you passed the full constructor as the input. I foolishly assumed that since I didn't get any pre-compilation errors about the function input that the way I was using the function was fine and the issue was with my class being a QObject. Since the function is a template it makes sense now why it only errors on compilation with the way its setup. Additionally, it makes complete sense why the errors were complaining about the copy constructor since the make_unique function would have to copy the instance I was creating inline by value with the incorrect syntax I was using.
I see the correct way to initialize this instance with make_unique is to pass the constructor input variables to the function directly.
I.e.
mCurrentSourcePtr = std::make_unique<MyClass>(var1, var2, this);
Thank you.
-
Won't let me mark your post as the answer for some reason. Sorry.
-
@oblivioncth said in std::unique_ptr with QObject derived class?:
Won't let me mark your post as the answer for some reason. Sorry.
Done for you :)