在Qt中的VideoWidget和Secure Socket Client示例中,在那里显示的代码将父窗口小部件中的子窗口小部件初始化,如下所示:
SslClient::SslClient(QWidget *parent)
: QWidget(parent), socket(0), padLock(0), executingDialog(false)
和
VideoPlayer::VideoPlayer(QWidget *parent)
: QWidget(parent)
, mediaPlayer(0, QMediaPlayer::VideoSurface)
, playButton(0)
, positionSlider(0)
, errorLabel(0)
然而,在代码中,我看到以下内容:
playButton = new QPushButton;
或在安全套接字客户端的情况下,这:
padLock = new QToolButton;
为什么在构造函数中将在代码中初始化时进行初始化?
答案 0 :(得分:3)
为什么在构造函数中将在代码中初始化时进行初始化?
这样实现是异常安全的。假设你有这个代码:
SslClient::SslClient(QWidget *parent)
: QWidget(parent), socket(0), padLock((QToolButton*)(0x0BEEF)), executingDialog(false) {
throw std::exception();
padLock = new QToolButton;
}
析构函数将删除padLock
,但它有垃圾值,并且您有未定义的行为。回想一下,删除nullptr是安全的(就像在C中调用free(NULL)
一样)。垃圾挂锁值显示未初始化时发生的情况。投掷表明可能会抛出一些干预代码。具体而言,如果分配不成功,任何干预new
都会抛出。 new
在失败时不会返回(如:它抛出std::bad_alloc
而不是返回,因此返回值的概念根本不适用。)
如果正在编写惯用的C ++,那么指针不应该是一个裸指针,而应该是std::unique_ptr
或QScopedPointer
,然后这个问题就会消失。您不必记住将指针初始化为零,并且您不必记得清理它。 RAII为您赢得了很多胜利。这就是你真正使用C ++时所使用的秘密武器。
C ++ RAII习惯用法本身并不存在于任何其他常见的编程语言中。在允许它的语言中(例如Java,C#,F#,Python,OCaml和Common Lisp),惯用的解决方法是定义更高阶的with_resource
函数,请参阅OCaml的示例,Java和Python以及Python again。基本上,在C ++以外的语言中,特别是在垃圾收集语言中,内存资源释放的处理方式与非内存资源释放不同。在C ++中,这些在RAII保护伞下是统一的。
答案 1 :(得分:0)
这是一种很好的做法。您应该始终初始化变量,即使它看起来没用。
这也适用于局部变量。这是一个很好的做法。
实际上,如果你这样做:
QString str;
然后str自动初始化。不幸的是,如果你这样做:
int value;
然后,值不会初始化为任何内容。它对速度有好处,但通常会导致错误。
对于构造函数,这是一个好主意,因为如果更改正文中的代码,最终可能无法初始化变量或其他...在列表中可能至少设置为null。初始化。
还有一个与异常相关联的原因,但这可能超出了Qt,它不会过多地使用异常。
答案 2 :(得分:0)
为什么在构造函数中将在代码中初始化时进行初始化?
我认为这只是因为如果实际的实例化后来推迟到另一个方法,对于intance,你将不会在某些操作中获得未初始化的成员,从而导致未定义的行为。
但是,在这种特殊情况下,如果不打算很快修改代码就没有多大意义。
它也可以归结为不同项目中的编码风格,但在这种特殊情况下,我不知道这受到官方Qt编码风格的限制。例如,在linux内核中,他们更喜欢 not 来像这样初始化它。