失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 细节决定成败之C++成员变量 构造函数初始化顺序

细节决定成败之C++成员变量 构造函数初始化顺序

时间:2022-02-05 11:44:12

相关推荐

细节决定成败之C++成员变量 构造函数初始化顺序

笔试题

class Runnable {protected:Runnable () : thread(NULL) {pthread_create(&thread, NULL, Runnable::Run, this);}~Runnable () {if (NULL != thread) {// Destroy thread.pthread_join(thread, NULL);}} protected:// Override this interface which extended runnable.virtual void Run (void) {}private:static void* Run (void* args) {Runnable* runnable = static_cast<Runnable*>(args);runnable->Run();return NULL;}private:pthread_tthread;};class Worker : public Runnable {public:Worker () : quit(false) {}~Worker () {// Set quit flag.quit = true;}protected:// Override thread run function.void Run (void) override { while (!quit) {// TODO somethine}}private:volatile bool quit; // Worker thread quit flag.// OTHER member variables};

请找出上面程序的Bug。

案例分析

上面笔试题的代码在一定概率下会崩溃或无响应,原因这与C++成员变量和构造函数的初始化顺序有关。在C++中任何变量或者对象的创建都可以看做如下两个步骤:

申请与类型一样大小的内存,基本等同于malloc(sizeof(T));调用该类型的构造函数实现对象的初始化操作,因为申请的内存的值是随机值;

这本身是两个步骤的事情让C++编译器合二为一,程序员在大意的情况下下很可能简化为一步,这就会让BUG有可乘之机。如果是通过层层的继承后类的构造函数,C++会优先调用父类的构造函数,再调用子类的构造函数,以此类推。

说道这里不知道读者们有没有意识到上面代码的Bug所在?问题就出在下面这块代码:

Worker () : quit(false) {}

Worker是Runnable的子类,也就是说程序会优先执行Runnable的构造函数:

Runnable () : thread(NULL) {pthread_create(&thread, NULL, Runnable::Run, this);}

从上面的代码可以看看出Runnable的构造函数创建了一个线程,这个线程的函数因为Worker类的重写而执行Worker::Run()。线程创建完成后程序开始执行Worker的构造函数,即将quit设置成false。问题就出在这里,线程优先于quit的初始化创建,在一定概率上线程函数在执行了quit还没有完成初始化,结果就是线程函数直接退出了,因为线程函数在判断quit值的时候还是一个随机值。程序认为线程创建了,但是线程函数已经退出了,外在表现就是僵死了。

除了上面说的Bug以外,在Worker析构的时候也存在问题,因为C++析构的顺序是优先执行子类的析构函数,再执行父类的析构函数,以此类推。这造成的问题是Worker对象已经执行析构函数了,但是线程函数可能还在执行,如果此时线程函数操作了Worker对象的成员变量就会有崩溃的风险。

一个看似很简单的代码,却因为一些小细节造成难以发觉的BUG,尤其是在CPU核数较少的工位机。因为在核数较多的服务器上,创建的线程可以立即执行,而核数较少时,创建的线程因为没有时间片大概率会落后于父线程,致使BUG难以发觉。

附加题

类内有多个成员变量,而成员变量的初始化顺序是定义成员变量时决定的,而不是构造函数里赋值的顺序决定的,记得网上有类似的笔试题。

class Type {public:Type() :b(2), a(1){}private:int a;int b;};

上面代码实际的执行顺序是a赋值为1,b赋值为2。

如果觉得《细节决定成败之C++成员变量 构造函数初始化顺序》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。