QObject::connect only work with last element when I stored class info into std::vector
-
I have an issue with connect signal and slot. The code looks like this.
class H : QObject { Q_OBJECT ... signals: void stateChanged(); ... } void H::CheckState() { emit stateChanged(); } class F : QObject { Q_OBJECT public slots: void StateChanged(); private: std::vector<H> m_hs; } void F::AddH(const H& h) { m_hs.push_back(h); // connect using loop // for(const auto& h : m_hs) // connect(&h, &H:stateChanged, this, &F::StateChanged); // connect for single h connect(&m_hs.back(), &H:stateChanged, this, &F::StateChanged); } void F::StateChanged() { }
F class has m_hs which is std::vector container contains multiple H class data.
If I use "connect using loop", all signal/slot works for all Hs.
But if I use "connect for single h", it only works for last pushed H class data.I believe it should work without for loop as it connect signal and slot multiple times for others except last element(H).
Do you have any idea about this?
-
Your H class is a QObject subclass I assume. You cannot copy a QObject (by design) but that is what you are attempting to do with your vector. (I am surprised that this compiled.) You should be heap allocating the H instances and storing pointers to them (if you need to), not instances.
-
Your H class is a QObject subclass I assume. You cannot copy a QObject (by design) but that is what you are attempting to do with your vector. (I am surprised that this compiled.) You should be heap allocating the H instances and storing pointers to them (if you need to), not instances.
@ChrisW67 Yes, you are right. Both H and F class are sub class of QObject. I am going to add it to the code.
Does this mean that F and H cannot have copy constructor as well?
Even the connected signals and slots are working when I used "connect using loop" code!
-
@ChrisW67 Yes, you are right. Both H and F class are sub class of QObject. I am going to add it to the code.
Does this mean that F and H cannot have copy constructor as well?
Even the connected signals and slots are working when I used "connect using loop" code!
@HarryC
No class derived fromQObject
(both yourF
&H
) can have a copy constructor.As @ChrisW67 said, create your instances via
H *h = new H
, store instd::vector<H *> m_hs
and then connect via// connect using loop for (const auto h : m_hs) connect(h, &H:stateChanged, this, &F::StateChanged);
See how that goes?
-
@HarryC
No class derived fromQObject
(both yourF
&H
) can have a copy constructor.As @ChrisW67 said, create your instances via
H *h = new H
, store instd::vector<H *> m_hs
and then connect via// connect using loop for (const auto h : m_hs) connect(h, &H:stateChanged, this, &F::StateChanged);
See how that goes?
-
@HarryC
No class derived fromQObject
(both yourF
&H
) can have a copy constructor.As @ChrisW67 said, create your instances via
H *h = new H
, store instd::vector<H *> m_hs
and then connect via// connect using loop for (const auto h : m_hs) connect(h, &H:stateChanged, this, &F::StateChanged);
See how that goes?
@JonB I confirm that it works well when I put pointer of H class to the vector even without using for loop to connect multiple times.
Do you guys usually not recommend using copy constructor/assignment operator for subclass of QObject even we can define them?
I have changed all relevant code to use pointer now based on std::shared_ptr. and, it works well.
But quite curious about your general patterns about using subclass of QObject as all functions that use signals/slots are subclass of QObject.I am going to set solved once I get answer for this question anyway.
Thanks for your help!
-
@HarryC said in QObject::connect only work with last element when I stored class info into std::vector:
Do you guys usually not recommend using copy constructor/assignment operator for subclass of QObject even we can define them?
You cannot define a copy constructor for a QObject derived class because QObject explicitly declares them private and deleted. See No Copy Constructor or Assignment Operator and Qt Objects: Identity vs Value.
So, for example:
#include <QCoreApplication> #include <QObject> class Test: public QObject { public: explicit Test(QObject *p = nullptr): QObject(p) { } Test(const Test& other): QObject(other) { } }; int main(int argc, char **argv) { QCoreApplication app(argc, argv); return 0; }
results in:
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I. -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o main.cpp main.cpp: In copy constructor ‘Test::Test(const Test&)’: main.cpp:7:40: error: use of deleted function ‘QObject::QObject(const QObject&)’ 7 | Test(const Test& other): QObject(other) { } | ^ In file included from /usr/include/x86_64-linux-gnu/qt5/QtCore/qcoreapplication.h:43, from /usr/include/x86_64-linux-gnu/qt5/QtCore/QCoreApplication:1, from main.cpp:1: /usr/include/x86_64-linux-gnu/qt5/QtCore/qobject.h:449:5: note: declared here 449 | Q_DISABLE_COPY(QObject) | ^~~~~~~~~~~~~~ make: *** [Makefile:358: main.o] Error 1
-
@HarryC said in QObject::connect only work with last element when I stored class info into std::vector:
Do you guys usually not recommend using copy constructor/assignment operator for subclass of QObject even we can define them?
You cannot define a copy constructor for a QObject derived class because QObject explicitly declares them private and deleted. See No Copy Constructor or Assignment Operator and Qt Objects: Identity vs Value.
So, for example:
#include <QCoreApplication> #include <QObject> class Test: public QObject { public: explicit Test(QObject *p = nullptr): QObject(p) { } Test(const Test& other): QObject(other) { } }; int main(int argc, char **argv) { QCoreApplication app(argc, argv); return 0; }
results in:
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I. -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o main.cpp main.cpp: In copy constructor ‘Test::Test(const Test&)’: main.cpp:7:40: error: use of deleted function ‘QObject::QObject(const QObject&)’ 7 | Test(const Test& other): QObject(other) { } | ^ In file included from /usr/include/x86_64-linux-gnu/qt5/QtCore/qcoreapplication.h:43, from /usr/include/x86_64-linux-gnu/qt5/QtCore/QCoreApplication:1, from main.cpp:1: /usr/include/x86_64-linux-gnu/qt5/QtCore/qobject.h:449:5: note: declared here 449 | Q_DISABLE_COPY(QObject) | ^~~~~~~~~~~~~~ make: *** [Makefile:358: main.o] Error 1
Hi Chris, thanks for your example. But when I tested with example on vs2019 with qt vs tools. Following code compiled and ran very well. Originally it didn't have copy constructor but I have added empty copy constructor for test purpose.
When I checked qobject.h file, I couldn't find deleted or private copy constructor or assignment operator. I am using Qt 5.15.2
update: Oh.. I found this
Q_DISABLE_COPY(QObject)
Which Q_DISABLE_COPY is#define Q_DISABLE_COPY(Class) \ Class(const Class &) = delete;\ Class &operator=(const Class &) = delete;
// main.cpp
#include "QtWidgetsApplication1.h" #include <QtWidgets/QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QtWidgetsApplication1 w; w.show(); return a.exec(); }
// QtWidgetsApplication1.cpp
#include "QtWidgetsApplication1.h" QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); }
// QtWidgetsApplication1.h
#pragma once #include <QtWidgets/QMainWindow> #include "ui_QtWidgetsApplication1.h" class QtWidgetsApplication1 : public QMainWindow { Q_OBJECT public: QtWidgetsApplication1(QWidget *parent = Q_NULLPTR); // empty copy constructor here QtWidgetsApplication1(const QtWidgetsApplication1& other) {} private: Ui::QtWidgetsApplication1Class ui; };
-
This:
// empty copy constructor here QtWidgetsApplication1(const QtWidgetsApplication1& other) {}
does not call the parent copy constructor (The sub-class copy's QObject instance will be default constructed). The equivalent in my code looks like:
Test(const Test& other): { }
and generates this warning:
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I. -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o main.cpp main.cpp: In copy constructor ‘Test::Test(const Test&)’: main.cpp:8:2: warning: base class ‘class QObject’ should be explicitly initialized in the copy constructor [-Wextra] 8 | Test(const Test& other) { } | ^~~~ main.cpp:8:19: warning: unused parameter ‘other’ [-Wunused-parameter] 8 | Test(const Test& other) { } | ~~~~~~~~~~~~^~~~~ g++ -Wl,-O1 -o test main.o /usr/lib/x86_64-linux-gnu/libQt5Gui.so /usr/lib/x86_64-linux-gnu/libQt5Core.so /usr/lib/x86_64-linux-gnu/libGL.so -lpthread
If these were two value classes then failing to call the parent class copy constructor would lead to an incomplete copy.