如何确保std :: call_once真的只调用一次

时间:2014-11-27 09:34:29

标签: c++ c++11 visual-studio-2013

我正在使用的一些代码使用std :: call_once,因此某些初始化只发生一次。但是,有些构造函数的全局对象最终可以调用初始化代码。

在下面的示例中,call_once实际上被调用了两次。我想这是因为once_flag构造函数在使用之前没有运行过。有没有办法解决这个问题,以便一些初始化代码只被调用一次而不必禁止全局变量?

#include <mutex>
#include <iostream>

using namespace std;

void Init();

class Global
{
public:
    Global()
    {
        Init();
    }
};

Global global;

once_flag flag;

void Init()
{
    call_once(flag, []{  cout << "hello" << endl;  });
}



int main(int argc, char* argv[])
{
    Init();
    return 0;
}

输出是:

hello
hello

1 个答案:

答案 0 :(得分:4)

根据规范,once_flag应该有一个简单的constexpr构造函数(例如,请参见此处 - http://en.cppreference.com/w/cpp/thread/once_flag)。有了它,如果它是全局/静态的,它实际上不是“构造的”(没有执行实际的函数),而更像是“值初始化” - 就像任何全局/静态POD类型一样。在这种情况下,不能让“{1}}正确初始化之前”运行任何构造函数。鉴于您对使用MSVC的评论,我想这可能是实施中的一个错误......

编辑: 根据下面的评论,MSVC根本不支持once_flag,因此您的选项在这里非常有限......如果您将所有内容都放在一个文件中,只需将constexpr“放在”所有内容之上使用它 - 文件中的构造函数按对象声明的顺序执行。如果您的用户分布在不同的文件中,您唯一的选择就是使用一个提供静态内部once_flag访问权限的功能 - 就像在这个答案http://www.parashift.com/c++-faq/static-init-order-on-first-use.html中一样。