【问题标题】:How to make sure a member function is called once如何确保成员函数被调用一次
【发布时间】:2013-03-06 22:46:16
【问题描述】:

假设我有一个名为 foo 的对象列表。我如何确保在创建第一个 foo 时调用成员 init() 但只调用一次。另外我如何确保当最后一个对象被销毁时,成员 quit() 被调用但只调用一次。

我知道 c++11 有 std::call_once 而对于 c++03 boost 有 boost::call_once。

我的第一次尝试看起来是这样的,但是退出的部分显然是错误的:

class foo
{
public:

    foo() { init(); }

    ~foo() 
    {
        // this is wrong
        quit();
    }

private:

    void init()
    {
        static boost::once_flag flag = BOOST_ONCE_INIT;
        boost::call_once( flag, [] () { /* init something */ }  );
    }

    void quit()
    {
        static boost::once_flag flag = BOOST_ONCE_INIT;
        boost::call_once( flag, [] () { /* quit something */ } );
    }
};

有没有办法仅依靠 c++ 工具来使其正确?

这是我实际尝试做的一个小补充。我正在尝试将 SDL 窗口包装在 c++ 类中,并希望调用 SDL_Init() 和 SDL_Quit 以及适当的时间。 我的第一次尝试在这里:http://pastebin.com/Y9X0UwUB

【问题讨论】:

  • call_once 用于多个线程尝试调用一个函数,并且只有其中一个真正成功调用它。
  • 您能否详细说明init() 的作用和foo 的含义?对此也有同样可行的解决方案,但最好的建模方法取决于您的情况。
  • @sftrabbit - call_once 也适用于单线程应用程序。不过,开销比其他方式可能要多一些。
  • @GManNickG 我正在尝试创建一个包含 SDL 窗口的 SDL 包装器。在创建第一个窗口之前,我需要调用 SDL_Init,而当最后一个窗口被销毁时,我喜欢调用 SDL_Quit。我的初稿在这里:pastebin.com/Y9X0UwUB

标签: c++ boost c++11


【解决方案1】:

听起来您希望这些方法为 static,然后还维护一个私有静态计数活动对象的数量,该计数在构造函数和析构函数中递增/递减并检查。

显然,如果这是一个多线程应用程序,您将需要某种形式的同步。

【讨论】:

  • 为什么静态方法会有帮助? once_flag 还不够吗?
  • @chhenning:我想 init/quit 方法是否是静态的并不重要,但听起来他们需要执行与任何特定类实例无关的操作,所以它会将它们声明为静态是有意义的(以记录意图)。
【解决方案2】:

您可以创建一个新类,在构造时调用 init 函数,在销毁时调用 quit 函数,然后让您的类的所有实例在构造时接收指向该类实例的 shared_ptr。

class foo_init_quit {
    public:
      foo_init_quit(){init();}
      ~foo_init_quit(){quit();}
};

std::vector<foo> do_something() {
    auto init_quit = make_shared<foo_init_quit>();
    std::vector<foo> vec;
    vec.emplace_back(init_quit);
    //...
    return vec;
}

【讨论】:

  • 我是这么想的。可能是调用 quit() 的好方法,但 init() 不起作用,因为 shared_ptr 应该不会被初始化。那里仍然需要一些东西。我认为这里可能有一个有趣的 hack。
  • @CrazyEddie 好吧,他没有说 init 函数应该做什么,所以我认为它不需要 foo 的实例来工作。
  • @Cubic:你能提供一个工作代码sn-p吗?我无法编译您的代码。谢谢!
【解决方案3】:
struct Funkay
{
    Funkay() : { ++count; init(); }
    ~Funkay() { --count; quit(); }

private:
    static size_t count;
    void init() { if (count == 1) ???; }
    void quit() { if (count == 0) ???; }
};
size_t Funkay::count = 0;

【讨论】:

  • 如果类是可复制/可移动的,那么减量可能比增量多得多。
猜你喜欢
  • 2011-05-09
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
相关资源
最近更新 更多