Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QObject::connect only work with last element when I stored class info into std::vector
Forum Updated to NodeBB v4.3 + New Features

QObject::connect only work with last element when I stored class info into std::vector

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 3 Posters 517 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    HarryC
    wrote on last edited by HarryC
    #1

    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?

    1 Reply Last reply
    0
    • C Offline
      C Offline
      ChrisW67
      wrote on last edited by
      #2

      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.

      H 1 Reply Last reply
      1
      • C ChrisW67

        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.

        H Offline
        H Offline
        HarryC
        wrote on last edited by HarryC
        #3

        @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!

        JonBJ 1 Reply Last reply
        0
        • H HarryC

          @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!

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @HarryC
          No class derived from QObject (both your F & H) can have a copy constructor.

          As @ChrisW67 said, create your instances via H *h = new H, store in std::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?

          H 2 Replies Last reply
          0
          • JonBJ JonB

            @HarryC
            No class derived from QObject (both your F & H) can have a copy constructor.

            As @ChrisW67 said, create your instances via H *h = new H, store in std::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?

            H Offline
            H Offline
            HarryC
            wrote on last edited by
            #5

            @JonB Okay Thanks! I will update after checking!

            1 Reply Last reply
            0
            • JonBJ JonB

              @HarryC
              No class derived from QObject (both your F & H) can have a copy constructor.

              As @ChrisW67 said, create your instances via H *h = new H, store in std::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?

              H Offline
              H Offline
              HarryC
              wrote on last edited by HarryC
              #6

              @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!

              1 Reply Last reply
              0
              • C Offline
                C Offline
                ChrisW67
                wrote on last edited by ChrisW67
                #7

                @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
                
                H 1 Reply Last reply
                1
                • C ChrisW67

                  @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
                  
                  H Offline
                  H Offline
                  HarryC
                  wrote on last edited by HarryC
                  #8

                  @ChrisW67

                  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;
                  };
                  
                  1 Reply Last reply
                  0
                  • H Offline
                    H Offline
                    HarryC
                    wrote on last edited by
                    #9

                    @ChrisW67 I realised I was wrong. It should be like this :

                    QtWidgetsApplication1(const QtWidgetsApplication1& other): : QMainWindow(other) {}
                    

                    This this I can see compile error successfully.

                    Thank you all!

                    1 Reply Last reply
                    0
                    • C Offline
                      C Offline
                      ChrisW67
                      wrote on last edited by ChrisW67
                      #10

                      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.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved