使用std::call_once实现实例方法仅调用一次时的错误排查与修复
问题
想要编写一个类,其中包含一个每个对象仅能实际执行一次的方法(可多次调用,但仅首次会执行操作)。示例代码如下:
#include <iostream> #include <functional> #include <mutex> class OneCallClass { private: std::once_flag f_once{}; public: void f() { std::call_once(f_once, []() { std::cout << "First call\n"; } ); } }; int main() { OneCallClass o; o.f(); // o.f(); // o.f(); }
该代码在Godbolt上运行失败,错误信息如下:
terminate called after throwing an instance of 'std::system_error' what(): Unknown error -1 Program terminated with signal: SIGSEGV
查阅cppreference上的std::call_once()文档后仍未发现问题,文档提到若有条件阻止std::call_once按指定执行会抛出std::system_error,但不清楚具体是什么条件。在栈上创建类实例,f_once已通过{}初始化,使用了规则零,未自定义构造函数、析构函数等。请问问题出在哪里,该如何修复?
原因分析
这个错误的核心原因是Godbolt在线编译器的运行环境默认未启用多线程支持。std::call_once依赖底层的线程同步机制(比如pthreads库),如果编译时没有链接对应的线程库,运行时就会因为无法初始化同步原语而抛出std::system_error,最终导致程序崩溃。
修复方案
在Godbolt的编译选项中添加线程库链接参数即可解决问题,具体操作:
- 找到界面右侧的编译器选项输入框
- 添加参数
-pthread(适用于GCC/Clang编译器)
添加参数后,编译命令会自动链接线程支持库,std::call_once就能正常工作。另外需要说明的是,你的代码逻辑本身完全正确:std::once_flag的默认初始化符合要求,std::call_once可以保证lambda仅被执行一次,多次调用f()不会重复执行操作。
内容的提问来源于stack exchange,提问作者Thomas W.
相关产品推荐
相关产品推荐

