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. unique_ptr for RAII?
Forum Updated to NodeBB v4.3 + New Features

unique_ptr for RAII?

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 423 Views 2 Watching
  • 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.
  • HoMaH Offline
    HoMaH Offline
    HoMa
    wrote on last edited by
    #1

    Hi all ! And thank you for reading this.
    I wanted to use a kind of RAII class to create database views. The constructor called a function, which created the views, the destructor deleted the views.
    Usually I would use a scoped object to get this "RAII" effect - but I want these objects to be member of another class (mainwindow) and the live time of the class should define the existence of the views.
    But ... the database is only opened in the constructor of mainwindow - so I "invented" this trick:

    The member of mainwindow is a unique_ptr<temporaryView>. After the database was opened, I make_shared<temporaryView> the object with the assumption, that at the end of the lifetime of mainwindow the views will be deleted.

    This worked fine - on Windows and on Linux in debug. But on Linux / w gcc the opt version removes the make_shared code ... the views are not created.

    This leads me to two questions: is there any reason not to use unique_ptr as RAII objects?
    And the obvious one: Is it OK that gcc kills my pointer?

    regards
    HoM

    *member declaration in mainwindow.h:*
    ...
    private:
       std::unique_ptr<tempView> list;
    
    *Initialization in mainwindow::mainwindow:*
    
    list = make_unique<tempView> (viewname, sql);
    
    *constructor of tempView:*
    
        tempView(const QString& name, const QString& sql, const QSqlDatabase& db = QSqlDatabase::database())
            : name(name) {
            Q_ASSERT(createView(name, sql, db));
        }
    
    Christian EhrlicherC 1 Reply Last reply
    0
    • HoMaH HoMa

      Why ... well ... it works ;)
      I know, that QObject does lifetime management, but I never got into details and I am not aware, how much overhead comes with making an object an QObject -so I avoided it. I did not need this knowledge so far ;)

      Here comes the example.
      I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

      main.cpp

      #include "mainwindow.h"
      #include <QApplication>
      #include "executesql.h"
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          prep();
          MainWindow w;
          w.show();
          return a.exec();
      }
      

      mainwindow.h

      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      
      #include <QMainWindow>
      
      QT_BEGIN_NAMESPACE
      namespace Ui { class MainWindow; }
      QT_END_NAMESPACE
      
      #include "executesql.h"
      
      
      
      
      struct tempview {
          tempview(QString n, QString sql) : name(n) {
              createView(name, sql);
          }
          ~tempview() {
              deleteView(name);
          };
          QString name;
      };
      
      
      
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          MainWindow(QWidget *parent = nullptr);
          ~MainWindow();
      
      private:
          Ui::MainWindow *ui;
      
          std::unique_ptr<tempview> autoview;
      };
      #endif // MAINWINDOW_H
      
      

      mainwindow.cpp

      #include <memory>
      
      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      
      MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
          autoview = std::make_unique<tempview> ("myView", "SELECT * FROM t");
      }
      
      MainWindow::~MainWindow()
      {
          delete ui;
      }
      

      executesql.h

      #ifndef EXECUTESQL_H
      #define EXECUTESQL_H
      
      #include <QString>
      
      void executeQ(QString sql);
      void prep();
      void createView(QString n, QString vsql);
      void deleteView(QString n);
      
      
      #endif // EXECUTESQL_H
      
      

      executesql.cpp

      
      #include <QtSql/QSqlDatabase>
      #include <QtSql/QSqlQuery>
      #include <QtSql/QSqlError>
      #include <QDebug>
      
      #include <QFile>
      
      void executeQ(QString sql)
      {
          QSqlQuery q;
          if(not q.exec(sql)) {
              qInfo() << q.lastError();
              Q_ASSERT(q.lastQuery().length());;
          }
      
      }
      
      void prep()
      {
          QString filename {"db.sqlite"};
          if( QFile::exists(filename))
              QFile::remove(filename);
          QSqlDatabase db =QSqlDatabase::addDatabase("QSQLITE");
          db.setDatabaseName(filename);
          db.open();
          executeQ("CREATE TABLE t (field STRING)");
      }
      
      void deleteView(QString n)
      {
          QString sql {"DROP VIEW %1"};
          sql =sql.arg(n);
          executeQ(sql);
      }
      
      void createView(QString n, QString vsql)
      {
          deleteView(n);
          QString sql {"CREATE VIEW %1 AS %2"};
          sql =sql.arg(n, vsql);
          executeQ(sql);
      }
      
      
      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by kshegunov
      #4

      @HoMa said in unique_ptr for RAII?:

      I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

      @HoMa said in unique_ptr for RAII?:

      Q_ASSERT(createView(name, sql, db));
      

      Q_ASSERT expands to nothing in release, so you shouldn't expect createView to be called at all.

      @HoMa said in unique_ptr for RAII?:

      Why ... well ... it works ;)

      What works? Wrapping a new in an object, sure it works. Is it necessary? Mostly not. Many things work for many a thing, that doesn't mean it's best, or even good. Why should I do gazillion heap allocations if I don't need to, is a question that often keeps me awake at night ...

      Read and abide by the Qt Code of Conduct

      HoMaH 1 Reply Last reply
      3
      • HoMaH HoMa

        Hi all ! And thank you for reading this.
        I wanted to use a kind of RAII class to create database views. The constructor called a function, which created the views, the destructor deleted the views.
        Usually I would use a scoped object to get this "RAII" effect - but I want these objects to be member of another class (mainwindow) and the live time of the class should define the existence of the views.
        But ... the database is only opened in the constructor of mainwindow - so I "invented" this trick:

        The member of mainwindow is a unique_ptr<temporaryView>. After the database was opened, I make_shared<temporaryView> the object with the assumption, that at the end of the lifetime of mainwindow the views will be deleted.

        This worked fine - on Windows and on Linux in debug. But on Linux / w gcc the opt version removes the make_shared code ... the views are not created.

        This leads me to two questions: is there any reason not to use unique_ptr as RAII objects?
        And the obvious one: Is it OK that gcc kills my pointer?

        regards
        HoM

        *member declaration in mainwindow.h:*
        ...
        private:
           std::unique_ptr<tempView> list;
        
        *Initialization in mainwindow::mainwindow:*
        
        list = make_unique<tempView> (viewname, sql);
        
        *constructor of tempView:*
        
            tempView(const QString& name, const QString& sql, const QSqlDatabase& db = QSqlDatabase::database())
                : name(name) {
                Q_ASSERT(createView(name, sql, db));
            }
        
        Christian EhrlicherC Online
        Christian EhrlicherC Online
        Christian Ehrlicher
        Lifetime Qt Champion
        wrote on last edited by
        #2

        @HoMa said in unique_ptr for RAII?:

        But on Linux / w gcc the opt version removes the make_shared code ... the views are not created.

        I'm pretty sure this is not correct - gcc will and must not remove this. Please provide a minimal, compilable example for this.

        For the rest - why? Not needed for QObject derived classes.

        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
        Visit the Qt Academy at https://academy.qt.io/catalog

        1 Reply Last reply
        0
        • HoMaH Offline
          HoMaH Offline
          HoMa
          wrote on last edited by
          #3

          Why ... well ... it works ;)
          I know, that QObject does lifetime management, but I never got into details and I am not aware, how much overhead comes with making an object an QObject -so I avoided it. I did not need this knowledge so far ;)

          Here comes the example.
          I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

          main.cpp

          #include "mainwindow.h"
          #include <QApplication>
          #include "executesql.h"
          
          int main(int argc, char *argv[])
          {
              QApplication a(argc, argv);
              prep();
              MainWindow w;
              w.show();
              return a.exec();
          }
          

          mainwindow.h

          #ifndef MAINWINDOW_H
          #define MAINWINDOW_H
          
          #include <QMainWindow>
          
          QT_BEGIN_NAMESPACE
          namespace Ui { class MainWindow; }
          QT_END_NAMESPACE
          
          #include "executesql.h"
          
          
          
          
          struct tempview {
              tempview(QString n, QString sql) : name(n) {
                  createView(name, sql);
              }
              ~tempview() {
                  deleteView(name);
              };
              QString name;
          };
          
          
          
          
          class MainWindow : public QMainWindow
          {
              Q_OBJECT
          
          public:
              MainWindow(QWidget *parent = nullptr);
              ~MainWindow();
          
          private:
              Ui::MainWindow *ui;
          
              std::unique_ptr<tempview> autoview;
          };
          #endif // MAINWINDOW_H
          
          

          mainwindow.cpp

          #include <memory>
          
          #include "mainwindow.h"
          #include "ui_mainwindow.h"
          
          MainWindow::MainWindow(QWidget *parent)
              : QMainWindow(parent)
              , ui(new Ui::MainWindow)
          {
              ui->setupUi(this);
              autoview = std::make_unique<tempview> ("myView", "SELECT * FROM t");
          }
          
          MainWindow::~MainWindow()
          {
              delete ui;
          }
          

          executesql.h

          #ifndef EXECUTESQL_H
          #define EXECUTESQL_H
          
          #include <QString>
          
          void executeQ(QString sql);
          void prep();
          void createView(QString n, QString vsql);
          void deleteView(QString n);
          
          
          #endif // EXECUTESQL_H
          
          

          executesql.cpp

          
          #include <QtSql/QSqlDatabase>
          #include <QtSql/QSqlQuery>
          #include <QtSql/QSqlError>
          #include <QDebug>
          
          #include <QFile>
          
          void executeQ(QString sql)
          {
              QSqlQuery q;
              if(not q.exec(sql)) {
                  qInfo() << q.lastError();
                  Q_ASSERT(q.lastQuery().length());;
              }
          
          }
          
          void prep()
          {
              QString filename {"db.sqlite"};
              if( QFile::exists(filename))
                  QFile::remove(filename);
              QSqlDatabase db =QSqlDatabase::addDatabase("QSQLITE");
              db.setDatabaseName(filename);
              db.open();
              executeQ("CREATE TABLE t (field STRING)");
          }
          
          void deleteView(QString n)
          {
              QString sql {"DROP VIEW %1"};
              sql =sql.arg(n);
              executeQ(sql);
          }
          
          void createView(QString n, QString vsql)
          {
              deleteView(n);
              QString sql {"CREATE VIEW %1 AS %2"};
              sql =sql.arg(n, vsql);
              executeQ(sql);
          }
          
          
          kshegunovK Christian EhrlicherC 2 Replies Last reply
          0
          • HoMaH HoMa

            Why ... well ... it works ;)
            I know, that QObject does lifetime management, but I never got into details and I am not aware, how much overhead comes with making an object an QObject -so I avoided it. I did not need this knowledge so far ;)

            Here comes the example.
            I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

            main.cpp

            #include "mainwindow.h"
            #include <QApplication>
            #include "executesql.h"
            
            int main(int argc, char *argv[])
            {
                QApplication a(argc, argv);
                prep();
                MainWindow w;
                w.show();
                return a.exec();
            }
            

            mainwindow.h

            #ifndef MAINWINDOW_H
            #define MAINWINDOW_H
            
            #include <QMainWindow>
            
            QT_BEGIN_NAMESPACE
            namespace Ui { class MainWindow; }
            QT_END_NAMESPACE
            
            #include "executesql.h"
            
            
            
            
            struct tempview {
                tempview(QString n, QString sql) : name(n) {
                    createView(name, sql);
                }
                ~tempview() {
                    deleteView(name);
                };
                QString name;
            };
            
            
            
            
            class MainWindow : public QMainWindow
            {
                Q_OBJECT
            
            public:
                MainWindow(QWidget *parent = nullptr);
                ~MainWindow();
            
            private:
                Ui::MainWindow *ui;
            
                std::unique_ptr<tempview> autoview;
            };
            #endif // MAINWINDOW_H
            
            

            mainwindow.cpp

            #include <memory>
            
            #include "mainwindow.h"
            #include "ui_mainwindow.h"
            
            MainWindow::MainWindow(QWidget *parent)
                : QMainWindow(parent)
                , ui(new Ui::MainWindow)
            {
                ui->setupUi(this);
                autoview = std::make_unique<tempview> ("myView", "SELECT * FROM t");
            }
            
            MainWindow::~MainWindow()
            {
                delete ui;
            }
            

            executesql.h

            #ifndef EXECUTESQL_H
            #define EXECUTESQL_H
            
            #include <QString>
            
            void executeQ(QString sql);
            void prep();
            void createView(QString n, QString vsql);
            void deleteView(QString n);
            
            
            #endif // EXECUTESQL_H
            
            

            executesql.cpp

            
            #include <QtSql/QSqlDatabase>
            #include <QtSql/QSqlQuery>
            #include <QtSql/QSqlError>
            #include <QDebug>
            
            #include <QFile>
            
            void executeQ(QString sql)
            {
                QSqlQuery q;
                if(not q.exec(sql)) {
                    qInfo() << q.lastError();
                    Q_ASSERT(q.lastQuery().length());;
                }
            
            }
            
            void prep()
            {
                QString filename {"db.sqlite"};
                if( QFile::exists(filename))
                    QFile::remove(filename);
                QSqlDatabase db =QSqlDatabase::addDatabase("QSQLITE");
                db.setDatabaseName(filename);
                db.open();
                executeQ("CREATE TABLE t (field STRING)");
            }
            
            void deleteView(QString n)
            {
                QString sql {"DROP VIEW %1"};
                sql =sql.arg(n);
                executeQ(sql);
            }
            
            void createView(QString n, QString vsql)
            {
                deleteView(n);
                QString sql {"CREATE VIEW %1 AS %2"};
                sql =sql.arg(n, vsql);
                executeQ(sql);
            }
            
            
            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by kshegunov
            #4

            @HoMa said in unique_ptr for RAII?:

            I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

            @HoMa said in unique_ptr for RAII?:

            Q_ASSERT(createView(name, sql, db));
            

            Q_ASSERT expands to nothing in release, so you shouldn't expect createView to be called at all.

            @HoMa said in unique_ptr for RAII?:

            Why ... well ... it works ;)

            What works? Wrapping a new in an object, sure it works. Is it necessary? Mostly not. Many things work for many a thing, that doesn't mean it's best, or even good. Why should I do gazillion heap allocations if I don't need to, is a question that often keeps me awake at night ...

            Read and abide by the Qt Code of Conduct

            HoMaH 1 Reply Last reply
            3
            • HoMaH HoMa

              Why ... well ... it works ;)
              I know, that QObject does lifetime management, but I never got into details and I am not aware, how much overhead comes with making an object an QObject -so I avoided it. I did not need this knowledge so far ;)

              Here comes the example.
              I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

              main.cpp

              #include "mainwindow.h"
              #include <QApplication>
              #include "executesql.h"
              
              int main(int argc, char *argv[])
              {
                  QApplication a(argc, argv);
                  prep();
                  MainWindow w;
                  w.show();
                  return a.exec();
              }
              

              mainwindow.h

              #ifndef MAINWINDOW_H
              #define MAINWINDOW_H
              
              #include <QMainWindow>
              
              QT_BEGIN_NAMESPACE
              namespace Ui { class MainWindow; }
              QT_END_NAMESPACE
              
              #include "executesql.h"
              
              
              
              
              struct tempview {
                  tempview(QString n, QString sql) : name(n) {
                      createView(name, sql);
                  }
                  ~tempview() {
                      deleteView(name);
                  };
                  QString name;
              };
              
              
              
              
              class MainWindow : public QMainWindow
              {
                  Q_OBJECT
              
              public:
                  MainWindow(QWidget *parent = nullptr);
                  ~MainWindow();
              
              private:
                  Ui::MainWindow *ui;
              
                  std::unique_ptr<tempview> autoview;
              };
              #endif // MAINWINDOW_H
              
              

              mainwindow.cpp

              #include <memory>
              
              #include "mainwindow.h"
              #include "ui_mainwindow.h"
              
              MainWindow::MainWindow(QWidget *parent)
                  : QMainWindow(parent)
                  , ui(new Ui::MainWindow)
              {
                  ui->setupUi(this);
                  autoview = std::make_unique<tempview> ("myView", "SELECT * FROM t");
              }
              
              MainWindow::~MainWindow()
              {
                  delete ui;
              }
              

              executesql.h

              #ifndef EXECUTESQL_H
              #define EXECUTESQL_H
              
              #include <QString>
              
              void executeQ(QString sql);
              void prep();
              void createView(QString n, QString vsql);
              void deleteView(QString n);
              
              
              #endif // EXECUTESQL_H
              
              

              executesql.cpp

              
              #include <QtSql/QSqlDatabase>
              #include <QtSql/QSqlQuery>
              #include <QtSql/QSqlError>
              #include <QDebug>
              
              #include <QFile>
              
              void executeQ(QString sql)
              {
                  QSqlQuery q;
                  if(not q.exec(sql)) {
                      qInfo() << q.lastError();
                      Q_ASSERT(q.lastQuery().length());;
                  }
              
              }
              
              void prep()
              {
                  QString filename {"db.sqlite"};
                  if( QFile::exists(filename))
                      QFile::remove(filename);
                  QSqlDatabase db =QSqlDatabase::addDatabase("QSQLITE");
                  db.setDatabaseName(filename);
                  db.open();
                  executeQ("CREATE TABLE t (field STRING)");
              }
              
              void deleteView(QString n)
              {
                  QString sql {"DROP VIEW %1"};
                  sql =sql.arg(n);
                  executeQ(sql);
              }
              
              void createView(QString n, QString vsql)
              {
                  deleteView(n);
                  QString sql {"CREATE VIEW %1 AS %2"};
                  sql =sql.arg(n, vsql);
                  executeQ(sql);
              }
              
              
              Christian EhrlicherC Online
              Christian EhrlicherC Online
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #5

              @HoMa said in unique_ptr for RAII?:

              QString sql {"CREATE VIEW %1 AS %2"};
              sql =sql.arg(n, vsql);
              
              QString sql {"DROP VIEW %1"};
              sql =sql.arg(n);
              

              Hello and welcome sql injection...

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              HoMaH 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                @HoMa said in unique_ptr for RAII?:

                QString sql {"CREATE VIEW %1 AS %2"};
                sql =sql.arg(n, vsql);
                
                QString sql {"DROP VIEW %1"};
                sql =sql.arg(n);
                

                Hello and welcome sql injection...

                HoMaH Offline
                HoMaH Offline
                HoMa
                wrote on last edited by
                #6

                @Christian-Ehrlicher you asked for the minimal code - right?

                1 Reply Last reply
                0
                • kshegunovK kshegunov

                  @HoMa said in unique_ptr for RAII?:

                  I'm on an ubuntu VM, QtCreator, GCC 64-bit, C++14, Qt 5.15.2. Debug is OK - Release fails :(

                  @HoMa said in unique_ptr for RAII?:

                  Q_ASSERT(createView(name, sql, db));
                  

                  Q_ASSERT expands to nothing in release, so you shouldn't expect createView to be called at all.

                  @HoMa said in unique_ptr for RAII?:

                  Why ... well ... it works ;)

                  What works? Wrapping a new in an object, sure it works. Is it necessary? Mostly not. Many things work for many a thing, that doesn't mean it's best, or even good. Why should I do gazillion heap allocations if I don't need to, is a question that often keeps me awake at night ...

                  HoMaH Offline
                  HoMaH Offline
                  HoMa
                  wrote on last edited by
                  #7

                  @kshegunov Q_ASSERT! That's it! I feel stupid now - Thank you !

                  1 Reply Last reply
                  1

                  • Login

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