2

我想使用 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)()。如果有人知道这里的替代解决方案,请提供帮助。

谢谢。

编辑::

另一个问题,如何使用 调用非静态成员函数call_once?我有这个类的一个非静态init()成员函数,但我找不到正确的语法来使用boost::call_once(). 或者我应该将init()其中使用的所有内容制作成静态的?

谢谢。

4

2 回答 2

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");
}

您可以在可调用对象之后传递任意数量的参数,它们都将被完美转发(包括 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工作方式与上述相同。

于 2012-12-11T16:37:50.250 回答
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;
}
于 2012-12-10T00:59:26.067 回答