【问题标题】:How to store non-copyable std::function into a container?如何将不可复制的 std::function 存储到容器中?
【发布时间】:2015-01-29 07:15:04
【问题描述】:

我想将回调存储在 C++11 中的向量或其他容器中。

这样做的一种方法是存储 std::function 的向量。 这适用于带有可复制参数的 lambda 或 std::bind。

但是,如果有一个不可复制(仅可移动)的参数,它将由于从 lambda/std::bind 内部类型到 std::function 的转换而失败...

#include <vector>

class NonCopyable {
public:
    NonCopyable() = default;
    NonCopyable(const NonCopyable &) = delete;
    NonCopyable(NonCopyable &&) = default;
};

int main() {
    std::vector<std::function<void()>> callbacks;
    callbacks.emplace_back([] {});

    NonCopyable tmp;
    callbacks.emplace_back(std::bind([](const NonCopyable &) {}, std::move(tmp)));
    // When converting the object returned by std::bind to a std::function,
    // a copy of the arguments happen so this code cannot compile.
    return 0;
}

有没有办法将 std::bind 参数移动到 std::function 中而不是复制它们?

【问题讨论】:

  • std::function 要求它包装的函子是 CopyConstructible,所以你运气不好。
  • 那么有没有更好的模式来存储回调?喜欢 packaged_task 还是其他类?
  • 存储指向函数或仿函数的指针,也许?
  • 您可以使用std::reference_wrapper&lt;NonCopyable&gt;,然后您可以将其放入std::vector&lt;std::function&lt;...&gt;&gt; 容器中。
  • 我对此进行了调查(使用 c++14 lambda 捕获,自定义 Functor 对象),看起来问题出在std::function,而不是容器或绑定处。 std::function 不能保存不可复制的对象。 stackoverflow.com/questions/7944635/… 所以你不能使用std::function

标签: c++ function c++11 move


【解决方案1】:

std::refstd::cref 用于在这种情况下避免复制对象(请参阅http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper)。

不确定我的问题是否正确,但这适合我:

#include <vector>
#include <functional>

class NonCopyable {
public:
  NonCopyable() = default;
  NonCopyable(const NonCopyable &) = delete;
  NonCopyable(NonCopyable &&) = default;
};

int main() {
    std::vector<std::function<void()>> callbacks;
    callbacks.emplace_back([] {});

    NonCopyable tmp;
    auto fun = std::bind([](const NonCopyable &) {}, std::cref(tmp));
    callbacks.emplace_back(fun);

    return 0;
}

编辑:如 cmets 中所述,请注意引用变量的生命周期!

【讨论】:

  • 我想他想用 tmp 存储乐趣,然后再调用乐趣。您的代码可以编译,但是当他调用 fun 时,tmp 将被释放。考虑将 main() 更改为 add_callbacks() 并在另一个函数中调用回调。
  • 是的,虽然您的评论对这种情况并不特别,但它更像是关于超出范围的变量的一般性陈述:)
【解决方案2】:

您可以使用std::shared_ptr,它是可复制的。类似的东西

using ptr = std::shared_ptr<NonCopyable>;
callbacks.emplace_back(std::bind([](const ptr &) {}, ptr(new NonCopyable())));

这样,NonCopyable 对象将在回调析构函数上自动析构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多