【问题标题】:Is it safe to change a function pointer (std::function) inside a called function?在被调用函数中更改函数指针(std::function)是否安全?
【发布时间】:2017-07-27 19:45:42
【问题描述】:

我有一个 std::function 指向一个函数。在这个函数中,我将指针更改为另一个函数。

std::function<void()> fun;

void foo() {
    std::cout << "foo\n";
}

void bar() {
    std::cout << "bar\n";
    fun = foo;
}

int main() {
    fun = bar;
    fun();
    fun();
}

我看不出有任何问题,而且效果很好(请参阅here),但是我不确定这样做是否合法。有什么我想念的吗?可能在 c++ 标准草案中(我很快查了一下,但到目前为止什么也没看到)。

【问题讨论】:

  • 这没有错。就是这样。
  • 合法但风格不好,因为全局变量的状态难以控制(无论如何你都应该尽量避免)。
  • 我有一个小游戏项目,我使用std::function 作为主循环回调(称为 60 次/秒)并分配给不同的方法来更改游戏状态(菜单选择、播放、暂停、等等。)。它运行良好。
  • @Aziuth 谢谢,但在实际代码中funfoobar 是一个类的成员。我发布的代码应该只是代表功能。

标签: c++ c++11 std-function


【解决方案1】:

这对于函数指针是合法的。

当您使用目标分配或构造std::function 时,它会创建目标的副本。在将函数分配给std::function 的情况下,这实际上将函数指针存储为目标对象。

当您调用operator() 时,需要返回如果您使用参数调用该目标会发生什么。

在作为副本存储在std::function 中的函数对象副本的“主体”内,如果您重新分配给std::function,则会破坏旧的目标函数对象。

销毁函数指针不会影响在指向的函数内执行的代码的有效性。

但是,如果您存储了函数对象(lambda、手动对象、其他 std::functions、std::bind 等),那么在分配时您会遇到通常的规则当this 被销毁时在类中运行方法。简而言之,您将无法再依赖实例的“本地状态”进行任何操作。

std::function<void()> fun;
struct bob {
  std::string name;
  bob* next = 0;
  void operator()() const {
    std::cout << name << "\n";
    if (next) fun = *next;
    // undefined behavior:
    // std::cout << name << "\n";
  }
};
bob foo = {"foo"};
bob bar = {"bar", &foo};

int main() {
  fun = bar;
  fun();
  fun();
}

live example.

如您所见,这可能很脆弱。

【讨论】:

    【解决方案2】:

    如果你在没有适当考虑和代码文档的情况下这样做,它可能会反过来咬你,但没有逻辑上的理由让它不起作用。

    在 c++ 中,函数的地址是不需要的,在返回编码中的函数内也是如此。

    如果它不适用于某种语言,编译器可能不会接受它 - 如果它是一个半体面的编译器。

    【讨论】:

    • 一般不同意最后一句话。在另一种情况下,编译器可能会像程序员想要的那样处理未定义的行为,但仍然是未定义的。
    • 半体面的编译器不会接受行为可能未定义的东西。在过去的几年里,c 编译器会接受最可怕的代码。幸运的是,大多数 c++ 编译器都非常严格。
    • int main(){return *(const int*)(nullptr);},用g++ -std=c++14 -O2 -Wall -Werrorno warning, no error, SIGSEGV编译。
    • 所以你说没有半体面的编译器。因为没有编译器可以捕获所有形式的未定义行为。
    • int* foo(){ int a = 1; int* p_a = &amp;a; return p_a;} int main(){ cout &lt;&lt; *foo() &lt;&lt; endl;} a 会死掉(尽管如果某些东西没有正确初始化,即使是空指针取消引用也可以完成)。这里有一些更有趣的:stackoverflow.com/questions/367633/…
    猜你喜欢
    • 1970-01-01
    • 2011-06-13
    • 2011-12-22
    • 2021-06-05
    • 2015-03-09
    • 1970-01-01
    • 2013-03-17
    • 2014-11-09
    • 1970-01-01
    相关资源
    最近更新 更多