【问题标题】:C++ Future handlingC++ 未来处理
【发布时间】:2021-01-26 17:53:46
【问题描述】:

我正在构建一个 C++ 程序,它使用 API 来尝试获取有关包裹跟踪信息的一些数据,其中一些方法正在返回期货,如果未来实现,我想将其返回到主程序。考虑以下几点:

std::future<ApiClass> myMethodReturningFuture() {
    /* some processing */
    std::future<ApiClass> future = api.call();
    return future;
}

我的问题是如何正确处理未来(例如,检查它是否包含正确的信息,调用 future.valid() 似乎总是返回 1)。此外,如果未来不完全有效,如何从此函数返回 NULL 或 nullptr ?让我们考虑一下这种情况:

std::future<ApiClass> myMethodReturningFuture() {
    /* some processing */
    try {
        std::future<ApiClass> future = api.call();
        return future;
    } catch (std::exception& e) {
        return nullptr // or NULL;
    }
}

上面的 sn-p 不能编译。即使我创建一个函数来返回一个指针,我也会收到关于“使用已删除函数 std::future”的错误。像这样的:

std::future<ApiClass>* myMethodReturningFuture() {
    /* some processing */
    try {
        std::future<ApiClass>* future = &api.call();
        return future;
    } catch (std::exception& e) {
        return nullptr // or NULL;
    }
}

【问题讨论】:

  • std::future::valid() 应该从默认构造的未来 std::future&lt;ApiClass&gt;(); 返回 false。您可以退回其中之一。
  • 如果未来不完全有效是什么意思?如果没有很好的方法来处理此方法中引发的异常,您可能应该在调用链的更高位置捕获它。

标签: c++ api asynchronous promise future


【解决方案1】:

future 基本上是一些共享状态的包装器。 valid 告诉你future 是否真的有一些共享状态。

如果 future 是默认构造的,或者如果它的共享状态已经被检索,或者它是移动的源,则 future 将没有共享状态,因此其他一些 future 现在拥有共享状态 this一个习惯了。

至少据我了解您在写什么,很有可能您真的只想按原样返回future,并且没有理由在返回之前检查它是否有效——特别是,如果您收到无效的future,则相当于您将返回的“空未来”信号,该信号将是默认构造的future,它将发出“不存在”的信号......通过其@987654329 @返回false。换句话说,您可以通过返回与您最初收到的完全相同的类型来表示缺少 future

我想如果你真的想要的话,可以future 中分离出“不存在”的信号。例如,你可以像这样定义你的函数:

std::optional<std::future<ApiClass>> myMethodReturningFuture() {

在一个理想的1 世界中,每个类都完全分解并且只有一个职责,std::future 可能不会存在 - 你会取而代之的是 std::optional&lt;std::shared_state&lt;T&gt;&gt; ,而optional 部分将负责说明它是否存在,而shared_state处理共享状态。但这不是我们生活的世界,所以futurevalid 基本上就像optional 一样,告诉你共享状态是否存在。

如果您要这样做,您需要考虑到 future 是可移动但不可复制的事实,因此当您将一个分配给变量时,您需要使用 std::move 来获取它退出该变量。例如,这里有一些简单(但完整)的代码来进行检查并返回std::optional&lt;std::future&lt;T&gt;&gt;

#include <optional>
#include <future>

struct ApiClass {
    int i;
};

struct Api { 
    std::future<ApiClass> call() const {
        // create and return a (trivial) future.
        return std::async(std::launch::async, []{ return ApiClass {1}; });
    }
};

std::optional<std::future<ApiClass>> myMethodReturningFuture() {
    Api api;
    // here we create a `future` object, so it's an lvalue, not an rvalue
    std::future<ApiClass> future {api.call()};
    // so when we want to create our optional<future>, we need to tell the
    // compiler to move instead of copying the object we created:
    return future.valid() == 1 ? std::make_optional(std::move(future)) : std::nullopt;
}

1.嗯,从一个角度来看是理想的。坦率地说,我不确定这种设计在实际使用中会变得如此理想。再说一次,我也不确定 `future` 在实际使用中是否完全理想。

【讨论】:

  • 谢谢!不过,我在使用 optional 时遇到了一些问题。我无法编译它,我不知道为什么:std::optional&lt;std::future&lt;ApiClass&gt;&gt; myMethodReturningFuture() { std::future&lt;ApiClass&gt; future = api.call(); return fut.valid() == 1 ? std::make_optional(future) : std::nullopt; } 我做错了吗?
  • error: no matching function for call to 'std::optional<:future> >::optional()' 这是我遇到的错误得到
  • @linnoob:我在答案中编辑了一些演示代码。
  • 太棒了。非常感谢!
猜你喜欢
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
  • 2020-07-09
相关资源
最近更新 更多