我想使用boost :: call_once()来实现线程安全的延迟构造 但是,单例场景,基本单例类有许多派生类,因此getInstance()函数接受一个参数来确定要初始化的派生类。代码看起来像,
Singleton * Singleton::getInstance(Input * a) {
if (!instance) {
instance = buildme(a); //buildme() will return a derived class type based on input a.
}
return instance;
}
我想使用boost::call_once()
,但看起来它只能用于没有参数void (*func)()
的函数。如果有人知道替代解决方案,请帮助。
感谢。
EDIT ::
另一个问题,如何使用call_once
调用非静态成员函数?我有这个类的非静态init()
成员函数,但我找不到使用boost::call_once()
调用它的正确语法。或者我应该使init()
和其中使用的所有东西都是静态的吗?
感谢。
答案 0 :(得分:7)
您可以使用boost::bind
将其他函数参数绑定到仿函数对象。像这样:
Input* input = ???;
boost::call_once(flag, boost::bind(&Singleton::getInstance, input));
您也可以使用boost::bind
来调用非静态成员函数,方法是将要调用该函数的类的实例传递给boost::bind
。
class Foo
{
public:
void func(int) { /* do something */}
};
Foo f;
boost::call_once(flag, boost::bind(&foo::func, &f, 10));
使用C ++ 11,您可以使用std::bind
,这是另一个例子。 boost::bind
非常相似。
#include <utility>
#include <functional>
#include <iostream>
#include <string>
void f(int x)
{
std::cout << "f(" << x << ")\n";
}
void g(int x, const std::string& y)
{
std::cout << "g(" << x << ", " << y << ")\n";
}
int main()
{
auto ten = std::bind(&f, 10);
auto example = std::bind(&g, 20, "Twenty");
ten();
example();
return 0;
}
答案 1 :(得分:7)
C ++ 11包含call_once的实现(受等效的Boost.Threads工具启发)。它使用可变参数模板和完美转发来获取任意数量的参数。
#include <mutex>
#include <string>
void only_called_once(int i, std::string const & str) {
// We only get here once.
}
void call_free() {
static std::once_flag once;
std::call_once(once, only_called_once, 42, "The answer");
}
你可以在callable之后传递任意数量的参数,它们都将被完美转发(包括r-value / l-value,const,volatile等)。
这也适用于会员功能。您只需将指针传递给对象(可转换为成员函数所属的类型)作为可调用后的第一个参数。
struct bar {
public:
void only_call_once(int i, std::string const & str);
};
void call_member() {
static std::once_flag once;
bar instance;
std::call_once(once, &bar::only_call_once, &instance, 42, "The answer");
}
如果你坚持使用Boost,那么你可以使用boost::bind
用于与另一个答案中已经解释过的目的相同的目的。 boost::bind
的成员函数的工作方式与上面相同,方法是将成员函数指针和实例作为以下参数传递。