【问题标题】:Self modifying vector of std::function segfaultstd::function segfault 的自修改向量
【发布时间】:2020-07-27 13:34:34
【问题描述】:

我正在尝试定义函数向量。当函数被调用时,它们可以在向量中添加或删除项目。

超简化,类似于下面的代码。

#include <functional>
#include <vector>

int main()
{
    using F = std::function<void()>;
    std::vector<F> v;
    v.push_back([&v]{
        puts("v0");
        v.push_back([]{puts("v1");});
        v.push_back([]{puts("v2");});
        v.push_back([]{puts("v3");});
        v.push_back([]{puts("v4");});
        v.push_back([]{puts("v4");});
        v.push_back([]{puts("v5");});
        v.push_back([]{puts("v6");});
    });
    v[0]();
}

代码编译正常,但运行时调用 V0 函数时出现段错误。

$ v0
$ Erreur de segmentation (core dumped)

我知道这个问题与向量重新分配有关(因为如果我在调用 V0 之前添加一个v.reserve(10); 它工作正常),但我仍然不明白该代码有什么问题以及为什么它不/应该不行。

【问题讨论】:

  • 它基本上是class C { void f() { delete this; DoSomethingMore(); };的精致版本
  • 作为一种解决方法,您可以调用v[0] 的副本:F{v[0]}();
  • 调用 v[0] 的副本实际上可以在我的实际用例中工作,感谢您的建议。

标签: c++ stdvector std-function


【解决方案1】:

但我仍然不明白该代码有什么问题以及为什么它不/不应该工作。

当向量重新分配时,存储在其中的对象在被复制后被销毁。

因此,正在执行的 lambda 已被销毁,当您尝试访问已销毁 lambda 的捕获引用 v 时,程序的行为未定义。

如果 std::function 的移动构造函数是 noexcept(它将在 C++20 中),vector 将移动元素,在这种情况下 lambda 将保持不变。

【讨论】:

  • 好的,我明白了。有没有办法让向量将 std::functions 移动到新分配的空间而不是复制/销毁它们?
  • @kriss 等待 C++20,其中 std::function 变为 noexcept 可移动。然后 vector 会移动它,并且 lambda 应该保持不变。
  • 我对这个解释有点困惑。虽然我可以理解,v[0] 的 lambda 在执行时由于重新分配而被破坏,但我不清楚与v 的关系。 v 指的是std::vector&lt;F&gt;,所以引用应该仍然完好无损? ([…]and when you attempt to access the captured reference v of the destroyed lambda[…])
  • @t.niese 引用存储在 lambda 中。如果 lambda 被破坏,引用将不会完好无损。即使引用的对象保持不变。就像您尝试通过已销毁类对象的引用成员访问对象一样。
  • 啊好吧,对不起,我明白了。
猜你喜欢
  • 2011-06-02
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
相关资源
最近更新 更多