为什么我可以多次调用boost::unique_future::get,而不像std::future

Why can I call boost::unique_future::get many times, unlike std::future?

本文关键字:future get std unique 我可以 调用 为什么 boost      更新时间:2023-10-16

我知道我们不能多次调用std::future::get,如果我们需要多次调用它,我们应该使用std::shared_future

但是我们可以多次调用boost::unique_future::get,尽管有boost::shared_future !

void test1()
{
    int i, j;
    std::future<int> fu1 = std::async([]{ return 42; });
    i = fu1.get();
    //j = fu1.get(); // error occur
    std::cout << i << std::endl;
    boost::unique_future<int> fu2 = boost::async([]{ return 43; });
    i = fu2.get();
    j = fu2.get(); // sucess...?
    std::cout << i << ' ' << j << std::endl;
    std::cin.get();
}

输出为:

42
43 43

我想了一会儿,然后尝试这个测试代码。

class TestCls
{
public:
    TestCls()
    {
        std::cout << "[TestCls] default constructor" << std::endl;
    }
    TestCls(const TestCls &other)
    {
        std::cout << "[TestCls] copy constructor" << std::endl;
    }
    TestCls(TestCls &&other)
    {
        std::cout << "[TestCls] move constructor" << std::endl;
    }
    TestCls &operator =(const TestCls &other)
    {
        std::cout << "[TestCls] copy assignment" << std::endl;
        return *this;
    }
    TestCls &operator =(TestCls &&other)
    {
        std::cout << "[TestCls] move assignment" << std::endl;
        return *this;
    }
};
void test2()
{
    TestCls a, b;
    std::cout << std::endl << "unique_future test begin" << std::endl;
    boost::unique_future<TestCls> fu1 = boost::async([]{ return TestCls(); });
    fu1.wait();
    std::cout << "first assignment" << std::endl;
    a = fu1.get();
    std::cout << "second assignment" << std::endl;
    b = fu1.get();
    std::cout << "unique_future test end" << std::endl;
    std::cout << std::endl << "shared_future test begin" << std::endl;
    boost::shared_future<TestCls> fu2 = boost::async([]{ return TestCls(); });
    fu2.wait();
    std::cout << "first assignment" << std::endl;
    a = fu2.get();
    std::cout << "second assignment" << std::endl;
    b = fu2.get();
    std::cout << "shared_future test end" << std::endl;
    std::cin.get();
}

输出为:

[TestCls] default constructor
[TestCls] default constructor
unique_future test begin
[TestCls] default constructor
[TestCls] move constructor
first assignment
[TestCls] move constructor
[TestCls] move assignment
second assignment
[TestCls] move constructor
[TestCls] move assignment
unique_future test end
shared_future test begin
[TestCls] default constructor
[TestCls] move constructor
first assignment
[TestCls] copy assignment
second assignment
[TestCls] copy assignment
shared_future test end

虽然boost::unique_future做的是"移动",而不是"复制",但允许多次调用get ..这怎么可能?

(我的boost版本是1.55.0,我的编译器是vc++ 2013)


如果我执行#define BOOST_THREAD_VERSION 4,则在第二次调用get()时发生异常。get()的多次调用是未定义的行为,直到版本3?或者直到版本3才被允许?

从文档中可以清楚地看出,至少有3个宏在你使用的东西中起着重要的作用

BOOST_THREAD_VERSION

设置库的版本,即使在4和3之间有突破性的变化,你似乎也没有问题。

第二个宏是BOOST_THREAD_PROVIDES_FUTURE,这个宏是一个开关,没有附加值,如果定义它启用"标准"期货,而不是unique_期货,你所说的unique_future只是一个占位符,在编译时由这个宏定义的东西。

从文件boost/thread/future.hpp

#if defined BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_FUTURE future
#else
#define BOOST_THREAD_FUTURE unique_future
#endif

在文件boost/thread/detail/config.hpp中你也有BOOST_THREAD_DONT_PROVIDE_FUTURE,这是另一个默认操作的开关

// PROVIDE_FUTURE
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE 
 && ! defined BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE
#endif

注意否定的!,这意味着如果你定义了BOOST_THREAD_DONT_PROVIDE_FUTURE,你应该得到由库记录的"真正的"unique_future

你基本上得到了默认的行为,事实上你正在使用库的版本4并不重要。

关于c++ 11及以后版本的边注:

std::async([]{ return 42; });

这在c++ 11中是不好的做法,在c++ 14中是未定义的行为,你应该总是为你的async指定一个启动策略。