假设我有一个名为caller的函数,它将调用一个名为callee的函数:
void caller()
{
callee();
}
现在可以在应用程序中多次调用调用者,并且您希望确保只调用一次调用者。 (一种延迟初始化),你可以使用一个标志来实现它:
void caller()
{
static bool bFirst = true;
if(bFirst)
{
callee();
bFirst = false;
}
}
我的意见是它需要更多代码,并且每次调用函数调用者时都需要再检查一次 对我来说更好的解决方案如下:(假设被调用者返回int)
void caller()
{
static int ret = callee();
}
但如果callee返回void,则无法处理这种情况,我的解决方案是使用逗号表达式:
void caller()
{
static int ret = (callee(), 1);
}
但问题在于,逗号表达式并不常用,人们在看到这行代码时可能会感到困惑,从而导致维护问题。
你有什么好主意确保只调用一次函数吗?
答案 0 :(得分:19)
你可以用这个:
void caller()
{
static class Once { public: Once(){callee();}} Once_;
}
答案 1 :(得分:12)
主题安全的:
static boost::once_flag flag = BOOST_ONCE_INIT;
boost::call_once([]{callee();}, flag);
答案 2 :(得分:7)
您可以通过函数指针隐藏该函数。
static void real_function()
{
//do stuff
function = noop_function;
}
static void noop_function()
{
}
int (*function)(void) = real_function;
来电者只需拨打function
即可完成第一次工作,并且不会对任何后续电话执行任何操作。
答案 3 :(得分:2)
你的第一个带有布尔标志bFirst
的变体只不过是 explict 手动实现编译器将为你做的暗示在你的其他变种中。
换句话说,在你所提出的所有变种中的典型实现中,将在生成的机器代码中另外检查一个布尔标志。所有这些变体的性能都是相同的(如果这是您的关注)。第一个版本中的额外代码可能看起来不那么优雅,但这对我来说似乎并不重要。 (包裹它。)
无论如何,你的第一个变体基本上是如何正常完成的(直到你开始处理多线程等问题。)
答案 4 :(得分:0)
受到一些人的启发,我认为使用宏来包装逗号表达式也会使意图明确:
#define CALL_ONCE(func) do {static bool dummy = (func, true);} while(0)