【问题标题】:Standard library function for running a function only once仅运行一次函数的标准库函数
【发布时间】:2014-10-19 10:58:51
【问题描述】:

这个 lambda 表达式的行为是否有一些标准库函数/类:

void some_func(int some_arg, float some_other_arg){
    static int do_once = ([](){
        // will be run once upon first function call but never again
        return 0; // dummy return value
    })();
    // will always run
}

写这个感觉就像一个黑客,但除了简单地调用main中的函数之外,我想不出另一种方法,但我实际上在做什么取决于模板参数,我需要使其尽可能通用。

对于上下文:
我为每个不同的模板参数注册了一个 atexit 函数,但只注册一次:第一次调用它。

【问题讨论】:

  • 也许是 std::call_once ? en.cppreference.com/w/cpp/thread/call_once
  • 但是我需要静态保留std::once_flag,这在单线程环境中并没有我已经在做的事情的优势。
  • 你应该让你的评论成为答案,我会接受它

标签: c++ c++11 lambda c++14


【解决方案1】:

也许您应该使用<mutex> 中的std::call_once
使用示例here

【讨论】:

  • 使用once_flag 实际上效果更好,因为我的函数运行一次依赖于父函数的另一部分
【解决方案2】:

我选择了std::call_once 选项,效果很好。

为此,我像这样重写了我的函数:

template<typename T>
void my_function(){
    static std::once_flag once;

    // function body (may return)

    // only called if rest of function successful
    std::call_once(once, [](){/* special sauce */});
}

@cdhowie,我觉得你不太明白我所说的static 是什么意思,它几乎与全球相反。

【讨论】:

  • 确实,我确实理解static 在这种情况下的含义,它在声明类成员时实际上意味着非常相似的东西——这意味着给定成员只有一个副本。这种方法确实可行,我的也是。只是实现它的不同方法。 :)
【解决方案3】:

正如 cmets 中所建议的,std::call_once() 是一个选项,但您不能将 std::once_flag 设为全局,否则只会调用一个函数——即使您提供不同的模板参数。听起来您只想为给定的模板参数调用一次函数。

如果是这种情况,那么您可以使函数成为模板类的静态部分,同时仍使用std::call_once() 机制:

template <typename T>
class initializer
{
public:
    static void call();

private:
    static void target();

private:
    static std::once_flag flag;
};

template <typename T>
void initializer<T>::call()
{
    std::call_once(flag, target);
}

template <typename T>
void initializer<T>::target()
{
    // Your code goes here.
}

template <typename T>
std::once_flag initializer<T>::flag;

现在您可以使用不同的T 类型调用initializer&lt;T&gt;::call(),并且保证每个不同的T 调用不超过一次。

【讨论】:

  • 静态存储 一个 once_flag 有点过分
  • @CoffeeandCode 每个不同的实例化有一个标志,它与您的答案完全相同。编译器将为我们两个答案中的每个不同的T 实例化一个标志。
  • 是的,我完全理解你的回答;但是为每个T 存储一个once_flag 定义类是矫枉过正的
  • 这是完全可能的,除了我们确实有可能重用具有不同实现的类。 (例如,可以将target 设为纯抽象。)在这两种情况下,它都会被编译为相似(如果不相同)的机器代码。
  • 是的,我确实喜欢让我的代码更通用(如问题所述),它确实具有能够专门化我的 target 函数的好处
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-21
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-09
相关资源
最近更新 更多