Created
March 15, 2016 06:53
-
-
Save 0xlitf/be16105d720885272980 to your computer and use it in GitHub Desktop.
如何保证某个函数只被调用一次
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 一个函数caller会在其内部调用另外一个函数callee,现在的情况是,caller可能会在多个地方被多次调用,而你希望callee只在第一次被调用时被调用一次。一般情况下,callee会是一个对环境或者资源的初始化工作。 | |
| 或许,从代码结构的角度来讲,你第一个想到的是把callee从caller中拿出来,放到某个合适的地方做初始化,这是个不错的方法,但相信我,在有些时候这并不是个有效的办法:你可能无法找个那个“合适的地方”,你也可能找到了但因此而失去lazy initialization的好处~~~。 | |
| 这里,我只想对这个问题找个好点的方法。 | |
| 第一个方法很简单,就是用个静态的flag来判断: | |
| 复制代码 | |
| static bool flag = false; | |
| if(!flag) | |
| { | |
| callee(); | |
| flag = true; | |
| } | |
| 复制代码 | |
| 这个可以非常完美的工作,但是代码感觉多了点,不够简洁。 | |
| 而且每个后续调用都要有个取反和判断操作,这对调用频繁的操作的性能是有影响的。另外,即使影响不大,从程序员感受的角度来看,你也不希望有多余的判断~~~ | |
| 哦,取反可以去掉: | |
| 复制代码 | |
| static bool flag = true; | |
| if(flag) | |
| { | |
| callee(); | |
| flag = false; | |
| } | |
| 复制代码 | |
| 但是,判断还是存在。 | |
| 【编辑:SO上讨论中有人指出,即使使用static变量,其实也会有一个判断操作,这一点说出了问题的根本,所以关于效率的论述是不必要的】 | |
| 当然,我们还有第二种更简洁的方法,假设callee的返回类型时int: | |
| static int dummy = callee(); // 1) | |
| 完了,利用静态变量只初始化一次的特点就可以实现,简洁,而且高效。 | |
| 但是,这里有个问题:如果callee的返回类型时void,那怎么办?你不能: | |
| static void dummy = callee(); | |
| static int dummy = (int)callee(); | |
| static int dummy = reinterpret_cast<int>(callee()); | |
| 因为void其实不是个类型,而是没有类型。 | |
| 即使你觉得自己很聪明,想出了下面这种方式: | |
| bool dummyfunc(void){return true;} | |
| static bool dummy = dummyfunc(callee()); | |
| 那也是不灵光的,不要以为callee返回void,把返回的void传给dummyfunc的参数就可以了,因为void根本就不是个类型,根本没有赋值,传值这个概念~~~ | |
| 幸亏C++中还有个叫逗号表达式的东西,说实话,C++用了7年多,这是我第一次发现逗号表达式这么可爱: | |
| 逗号表达式会这个计算每个子表达式,并返回最后一个子表达式的值 | |
| 于是,就有了这个解决方案: | |
| static bool dummy = (callee(), true); // 2) | |
| static auto a = (connect(imageCapture, &QCameraImageCapture::imageCaptured, [=](int i, QImage image) | |
| { | |
| QLabel *label = new QLabel(); | |
| label->setPixmap(QPixmap::fromImage(image)); | |
| label->show(); | |
| }), true); | |
| 也是同样的简洁、高效。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment