C++11 default destructor and std::unique_ptr



  • Hi!

    I'm playing around with C++11 features to improve my Qt programs which by now rely mostly on C++98.

    I have a QWidgets application with a QMainWindow derived MainWindow and a Ui::MainWindow generated with Qt Designer. Now I tried to be super smart and instead of keeping a pointer Ui::MainWindow *ui; I keep a std::unique_ptr to the ui. Thus I don't need the usual~MainWindow() with delete ui; inside anymore. This is what the code looks like:

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <memory>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
    
    private:
        std::unique_ptr<Ui::MainWindow> m_ui;
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent)
        , m_ui(new Ui::MainWindow)
    {
        m_ui->setupUi(this);
    }
    

    That was my naive theory. Turns out it doesn't compile. The error says:

    /usr/include/c++/4.8/bits/unique_ptr.h:-1: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Ui::MainWindow]':
    
    /usr/include/c++/4.8/bits/unique_ptr.h:184: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Ui::MainWindow; _Dp = std::default_delete<Ui::MainWindow>]'
    
    /usr/include/c++/4.8/bits/unique_ptr.h:65: error: invalid application of 'sizeof' to incomplete type 'Ui::MainWindow'
      static_assert(sizeof(_Tp)>0,
                          ^
    

    I tried adding ~MainWindow() = default; but that didn't help. Can someone please explain to me what's going on here?


  • Qt Champions 2016

    @Wieland

    #include "ui_mainwindow.h"
    

    in the header, not only in source?
    :)



  • @kshegunov Hi! Before we move to the question why the forward declaration of Ui::MainWindow in the header might not be sufficient: Why doesn't the ~MainWindow() = default; work? Because, as soon as I add ~MainWindow(); to the header and MainWindow::~MainWindow() {} to the source it compiles.


  • Qt Champions 2016

    @Wieland
    Funny thing with templates. Instantiation happens where you do the specialization (in this case the header). The compiler needs the members to be fully defined to generate the default destructor (i.e. it needs to know the destructor of UI::MainWindow in this case and this is happening while parsing the header no less).

    When you provide your own destructor (in source) the compiler doesn't need to call the destructor of the unique_ptr class (thus the destructor of the Ui::MainWindow class) and you're fine only using forward declarations :)

    I hope I explained it understandably.

    :)



  • @kshegunov Ah.. sounds logical. Thank you!


  • Qt Champions 2016

    @Wieland
    My pleasure! :D



  • If someone needs a comprehensive 8 pages long explanation for what's exactly happening here, I recommend reading "Item 22: When using the Pimpl Idiom, define special member functions in the implementation file" from "Effective Modern C++" by Scott Meyers.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.