【问题标题】:can an std::promise be made from a non-POD object?可以从非 POD 对象中生成 std​​::promise 吗?
【发布时间】:2015-03-11 16:07:56
【问题描述】:

我的应用程序所做的其中一件事是侦听和接收来自套接字的有效负载。我从不想阻止。在收到的每个有效负载上,我想创建一个对象并将其传递给工作线程,直到稍后再忘记它,这就是原型代码的工作方式。但是对于生产代码,我想通过使用方便的异步方法来降低复杂性(我的应用程序很大)。 async 接受一个由承诺创造的未来。为此,我需要在下面由 Xxx 类表示的非 POD 对象上创建一个 Promise。我没有看到任何方法可以做到这一点(请参阅下面的示例代码中的错误)。在这里使用异步是否合适?如果是这样,我如何构造一个比 int 更复杂的 promise/future 对象(我看到的所有代码示例都使用 int 或 void):

#include <future>
class Xxx //non-POD object
{
  int i;
public:
  Xxx( int i ) : i( i ) {}
  int GetSquare() { return i * i; }
};

int factorial( std::future< Xxx > f )
{
  int res = 1;
  auto xxx = f.get();
  for( int i = xxx.GetSquare(); i > 1; i-- )
  {
    res *= i;
  }
  return res;
}

int _tmain( int argc, _TCHAR* argv[] )
{
  Xxx xxx( 2 ); // 2 represents one payload from the socket
  std::promise< Xxx > p; // error: no appropriate default constructor available
  std::future< Xxx > f = p.get_future();
  std::future< int > fu = std::async( factorial, std::move( f ) );
  p.set_value( xxx );
  fu.wait();
  return 0;
}

【问题讨论】:

  • 你试过给Xxx一个默认的ctor吗?
  • 为什么不直接将xxx 传递给异步函数呢?你真的需要双向future 通信吗?这只是意味着两个线程都在等待对方。
  • 我明白了。由于我已经拥有有效负载数据,因此无需对其做出承诺/未来。只需将 asnyc 的 _Fty&& _Fnarg、_ArgTypes&&... _Args 构造函数与我的复杂参数一起使用。
  • 对。您使用 future 将结果返回 out of async,但您不需要使用一个来传递任何内容。

标签: c++ asynchronous promise


【解决方案1】:

正如 Mike 已经回答的那样,这绝对是 std::promise 的 Visual C++ 实现中的一个错误,你所做的应该可以工作。

但我很好奇你为什么需要这样做。也许还有一些其他要求您没有展示以使示例保持简单,但这将是编写该代码的明显方式:

#include <future>

class Xxx //non-POD object
{
  int i;
public:
  Xxx( int i ) : i( i ) {}
  int GetSquare() { return i * i; }
};

int factorial( Xxx xxx )
{
  int res = 1;
  for( int i = xxx.GetSquare(); i > 1; i-- )
  {
    res *= i;
  }
  return res;
}

int main()
{
  Xxx xxx( 2 ); // 2 represents one payload from the socket
  std::future< int > fu = std::async( factorial, std::move( xxx ) );
  int fact = fu.get();
}

【讨论】:

  • 是自动 xxx = f.get();仍然有必要,因为我将来不会再通过了?
  • 糟糕,很好发现。我忘了改那一点,现​​在已经修好了。
  • 这确实是一个错误。我已经提交了bug report。这个错误甚至被列为 文件中的待办事项(“// TODO: _Associated_state ctor 假定 _Ty 是默认可构造的”),因此开发人员已经很清楚了。
【解决方案2】:

听起来您的实现有缺陷。应该不需要默认构造函数(根据 [utility.arg.requirements] 的一般库要求),并且 GCC 接受您的代码(在将奇怪的 Microsoftish _tmain 更改为标准 main 之后)。

我会切换到不同的编译器和操作系统。这对你来说可能不是一个选择,所以也许你可以给这个类一个默认的构造函数来让它快乐。

【讨论】:

  • 是的,这绝对是实现中的一个错误。 promise&lt;Xxx&gt; 应该创建一个未初始化的缓冲区,并且只在调用 set_value 时构造一个 Xxx 对象。另一种解决方法是使用boost::promise 而不是std 一个
  • 我是一个 C++ MFC-hugger 从很久以前就开始了。我跳过了 Java 和 C# 技术题外话,很高兴将这些新的 ISO 并行化功能与我的所有其他 C++ 库(GUI、加密等)一起使用。实际上,根据 2014 Build 的 Herb Sutter 所说,是 MS 将他们的异步实现提交给标准社区以供纳入。我假设 [utility.arg.requirements] 声明您应该能够在承诺中传递任何类型的 arg?
  • [utility.arg.requirements] 并不特定于promise,它只是说“通常,不需要默认构造函数。”
猜你喜欢
  • 1970-01-01
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多