导致崩溃的递归构造函数?

时间:2018-03-07 16:59:09

标签: c++ qt user-interface

所以,我认为我已经足够开始尝试一些框架/ apis,所以我正在考虑学习qt框架,以便我可以开始开发一些简单的gui应用程序,

无论如何,我注意到qt MainWindow.cpp文件中有一个奇怪的东西

  MainWindow::MainWindow(QWidget *parent) :  
    QMainWindow(parent),  
    ui(new Ui::MainWindow)  
{  
    ui->setupUi(this);  
}

所以我理解ui是一个指针,我们将一个新的MainWindow对象分配给该指针

但是每当程序崩溃时我用自己的代码做同样的事情

#include <iostream>

using namespace std;


    class Sample{

     public:
         Sample* ss; [c++]
         string text = "hey ya";
         explicit Sample()
         :ss(new Sample){

           cout << "hi" << endl; // doesn't print hi?
         }

         void print(){
            cout << ss->text << endl;
         }

         ~Sample(){

           delete ss;
         }
    };

    int main()
    {
        cout << "Hello world!" << endl;
        Sample s;
        return 0;
    }

起初我认为崩溃是因为无限递归,每个构造函数将继续调用一个新的样本

但是如果是这样的话,不应该打印到控制台吗?

为什么这个代码在qt中有效,但是我的工作还没有成功,我的意思是它做了同样的事情,

请注意,在qt MainWindow标头中,构造函数是标记显式的,如果这有任何区别,我尝试将我的Sample类中的构造函数标记为显式,但仍然崩溃

感谢

2 个答案:

答案 0 :(得分:4)

  

但是每当我用自己的代码做同样的事情时   程序崩溃

它不是“几乎相同” - 在外观上 - 有些,但是当你不注意细节时看起来可能是欺骗,但在功能上它远非如此。

您的代码是一个无限创建自己的类,该类的每个新实例都创建另一个实例,该实例创建另一个实例,依此类推,直到您遇到某些(运行时,操作系统或硬件)限制并且您的应用程序崩溃。即使是第一个创建的对象,您的代码也永远不会到达“hi”部分。

这与Qt示例代码无关。在该代码中,类不会在构造函数中创建自身的新实例。它创建了一个从UI表单生成的不同类。虽然类名相同,但是同一个类,因为它存在于Ui命名空间中。这些类名称相同,因为它们是互补的,它们不一定是,但这就是Qt在为您生成代码时所做的事情。这是有道理的,因为它清楚地表明哪个窗口小部件类对应于哪个窗体类。

MainWindowUi::MainWindow 不是相同的类,这就是为什么它有意义并且确实有效。

请注意,C ++甚至不会让你在同一个类中有一个类的实例,既不是直接也不是通过间接继承或聚合,这是默认的no-no,因为无限递归对于编译器来说是显而易见的,无论多么深刻它可能是嵌套的。但是有一个指针是可以的,因为指针基本上只是对另一个可以经常使用的对象的引用,你必须承担责任,即使它创建了另一个相同类型的对象,而不是简单地引用一个预先存在的对象,您可以限制该行为,使其不会遇到无限递归。

struct RTest {
    RTest(int & d) {
      qDebug() << "hi" << d;
      t = d++ < 10 ? new RTest(d) : nullptr;
    }
    RTest * t;
};

在这种情况下,递归限制为10的深度。请注意,如果在初始化列表中执行指针初始化,则不会从0到10获得hi,而只会{{1}在递归完成之前,将无法访问第一个对象的构造函数的主体,这就是为什么你永远不会将代码传递给hi 11

答案 1 :(得分:1)

  

但如果是这样的话,不应该打印到控制台吗?

不。构造类时,首先会发生类成员初始化列表。这意味着

ss(new Sample)

在您进入构造函数体之前发生。由于该行创建了一个新的Sample,您初始化Sample,这将创建另一个新的Sample,此过程将永久发生,直到操作系统停止或进程崩溃