Theo cppreference, sau khi gọi std::future::get
:std :: tương lai vẫn còn hiệu lực sau khi gọi get() (mà ném một ngoại lệ)
hợp lệ() là sai sau khi một cuộc gọi đến phương pháp này.
Bên cạnh đó, từ cplusplus.com:
Khi nhà nước chia sẻ đã sẵn sàng, chức năng unblocks và lợi nhuận (hoặc ném) phát hành nhà nước chia sẻ của nó. Điều này làm cho đối tượng tương lai không còn hợp lệ nữa: chức năng thành viên này sẽ được gọi một lần tối đa cho mọi trạng thái được chia sẻ trong tương lai.
Và dưới ngoại lệ an toàn:
Chức năng ném ngoại lệ được lưu trữ trong tình trạng chia sẻ khi các nhà cung cấp làm cho nó sẵn sàng bằng cách thiết lập nó để một ngoại lệ. Lưu ý rằng trong trường hợp này, bảo đảm cơ bản được cung cấp, với đối tượng tương lai đang được sửa đổi để không còn là một tương lai hợp lệ (mà chính nó là một trạng thái hợp lệ cho đối tượng thuộc loại này, mặc dù tên của nó).
Không có mô tả nào khác biệt giữa cuộc gọi đến get
trả về giá trị so với giá trị trả về ngoại lệ liên quan đến việc vô hiệu hóa đối tượng trong tương lai.
Tuy nhiên, hành vi được mô tả không phải là những gì tôi nhìn thấy với mã ví dụ này:
#include <chrono>
#include <future>
#include <iostream>
#include <stdexcept>
int foo()
{
throw std::runtime_error("foo exception");
}
int main()
{
std::future<int> futInt;
futInt = std::async(std::launch::async, []() { return foo(); });
while(!(futInt.valid() && futInt.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready))
;
if(futInt.valid())
{
int val;
try
{
val = futInt.get();
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
if(futInt.valid())
{
std::cout << "This is TOTALLY UNEXPECTED!!!" << std::endl;
}
else
{
std::cout << "This is expected." << std::endl;
}
return 0;
}
Sản lượng tôi thấy là:
foo exception
This is TOTALLY UNEXPECTED!!!
Tôi đang sử dụng Visual Studio cao cấp năm 2013, Bản cập nhật phiên bản 12.0.30501.00 2. Đây có phải là lỗi với trình biên dịch hay không, trên thực tế, hành vi đúng trong trường hợp ngoại lệ? Tôi đã không thể tìm thấy bất kỳ báo cáo lỗi liên quan đến điều này, do đó, không chắc chắn nếu nó đã được mong đợi hành vi.
Edit - < tương lai > thực hiện điều tra
Đào vào việc thực hiện std::future
một chút, đối tượng _Associated_state
được đánh dấu _Retrieved = true;
SAU kiểm tra và ném ngoại lệ liên quan (nếu có):
virtual _Ty& _Get_value(bool _Get_only_once)
{ // return the stored result or throw stored exception
unique_lock<mutex> _Lock(_Mtx);
if (_Get_only_once && _Retrieved)
_Throw_future_error(
make_error_code(future_errc::future_already_retrieved));
if (_Exception)
_Rethrow_future_exception(_Exception);
_Retrieved = true;
_Maybe_run_deferred_function(_Lock);
while (!_Ready)
_Cond.wait(_Lock);
if (_Exception)
_Rethrow_future_exception(_Exception);
return (_Result);
}
Đoán của tôi là kiểm tra ngoại lệ và _Retrieved = true;
cần được hoán đổi - đối tượng sẽ được chụp iately được thiết lập như được lấy ra (sau khi kiểm tra _Get_only_once
) và sau đó tất cả các logic khác nên làm theo. Ergo, lỗi trình biên dịch.
Edit - workaround
Tôi nghĩ rằng sau là đủ thay vì trực tiếp gọi get
cho đến khi một sửa chữa được thực hiện:
template<typename T>
T getFromFuture(std::future<T>& fut)
{
try
{
return fut.get();
}
catch(...)
{
fut = {};
throw;
}
}
sau khi in '" Đây là ĐẦY ĐỦ KHÔNG HOÀN THÀNH !!! "', điều gì sẽ xảy ra nếu bạn 'futInt.get()' một lần nữa? – YSC
g ++ 4.8.4 cho "ngoại lệ foo" và "Điều này được mong đợi". –
@YSC - "ngoại lệ foo" được ném lại (tôi đã thử nghiệm điều này bằng cách sao chép bên trong của câu lệnh if đầu tiên ngay sau khi cout). – AlphaXerion