这是一些Qt代码:(5.1.1)
QTreeWidgetItem *rootItem;
rootItem->setText(0, "Column 1");
rootItem->setText(1, "Column 2");
rootItem->setText(2, "Column 3");
rootItem->setText(3, "Column 4");
ui->treeWidget->addTopLevelItem(rootItem);
Messages::ShowMessage(rootItem->childCount());
上面的代码可以运行,人们会发现运行时错误,因为rootItem是未初始化但却有效。我在这里错过了什么?我正在使用Qt Creator。
他们做过某种自动初始化吗?如果是,我应该在哪里关闭它?我运行程序,我得到4列。这毫无意义。
但是当我尝试实际初始化指针时,我只得到1列。
QTreeWidgetItem *rootItem = new QTreeWidgetItem(ui->treeWidget);
rootItem->setText(0, "Column 1");
rootItem->setText(1, "Column 2");
rootItem->setText(2, "Column 3");
rootItem->setText(3, "Column 4");
ui->treeWidget->addTopLevelItem(rootItem);
我错过了什么?
答案 0 :(得分:4)
它是未定义的行为,因此当您遇到它们时,您不能指望任何逻辑上合理或一致的行为。
但实际上,通过将指针设置为nullptr
或NULL
,可以提高运行时系统检测到这类错误的几率。
QTreeWidgetItem *rootItem = nullptr;
同样在调试模式下运行程序也可能有所帮助,许多现代编译器在检测到它们时都会发出诊断和警告(你应该总是启用它们,将它们设置为最高,最偏执的级别)。
但请注意,上述内容并不保证您能做任何事情,并且您仍然需要制作正确且表现良好的代码。
这里有很多建议让你使用普通对象(堆栈分配,非指针指向的),或者如果你不能(如果你的可怜的库对它们过敏那么 [1] ),总是使用指针包装器,例如std::unique_ptr
或std::shared_ptr
,或者你的库提供的并且能够消化的东西。
[1] 我不喜欢那些类型的库。
答案 1 :(得分:3)
如果你添加
QMAKE_CXXFLAGS += -Wall
或更不严格:
QMAKE_CXXFLAGS += -Wuninitialized
到你的.pro
文件,编译器会抱怨并且你会发现这个问题 - 你将被迫使用类似的东西:
QTreeWidgetItem *rootItem = NULL;
或
QTreeWidgetItem *rootItem = new QTreeWidgetItem();
答案 2 :(得分:2)
C ++不保证未定义的行为不会出现,并且你不幸遇到了这个问题。未初始化指针所指向的内存可能已被抢占,因此没有运行时错误,但你不能依赖它。
大多数编译器都会发出警告(你打开它们吗?)。此外,还有许多在调试版本中将指针初始化为某个虚拟值以表示错误 - 并且您在运行时会遇到访问冲突崩溃。
答案 3 :(得分:1)
人们会发现运行时错误。我在这里缺少什么?
使用无效指针会产生未定义的行为。这并不一定意味着运行时错误;这意味着任何事情都可能发生。
他们做过某种自动初始化吗?
据推测,这是班级内的自动变量。如果您没有指定初始化器,则它们根本不会初始化(无论是有效的还是“已知的无效”值);初始值是不确定的(无论是在那块内存中的垃圾),使用该值会给出未定义的行为。
指针完全有可能指向可寻址内存块,在这种情况下程序可能会起作用。该内存将不包含正确初始化的QTreeWidgetItem
,并且可能包含您正在破坏的其他对象,因此这可能会在以后导致更多难以理解的错误。
如果是,我应该在哪里关闭它?
启用编译器警告(-Wall
或特定-Wuninitialized
,如果您正在使用GCC)应该捕获大多数未初始化变量的使用。避免指针和new
除非你真的需要它们也会有所帮助,虽然我不知道在处理Qt时这是否是一个选项。
(我不太了解Qt回答最后一个问题,对不起)。