2015-11-24 18 views
8

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; 
    } 
} 
+0

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

+2

g ++ 4.8.4 cho "ngoại lệ foo" và "Điều này được mong đợi". –

+0

@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

Trả lời

3

tôi biên soạn trên Linux với gcc 5.2.0 và kêu vang 3 .7.0 - cả hai lần với 64 bit. Chạy chương trình luôn luôn dẫn đến

foo exception 
This is expected. 

Có vẻ với tôi như Visual 2013 xử lý này không chính xác. Xem thêm:

C++ §30.6.6/16-17

Ném: ngoại trừ lưu trữ, nếu một ngoại lệ đã được lưu trữ trong tình trạng chia sẻ.

Điều kiện sau:valid() == false.

Điều kiện sau được đề cập sau khi ném và do đó phải luôn giữ, ngay cả khi ngoại lệ được ném. Ít nhất đó là sự giải thích của tôi, mặc dù tôi không nói được tiêu chuẩn.

Tôi đoán bạn có lẽ nên thử cũng với Visual Studio 2015 và báo cáo lỗi nếu điều đó cho thấy sự xử lý tương tự.

+0

Đã xác nhận cùng một hành vi sai trái trong VS 2015. Cảm ơn bạn đã tham khảo Tiêu chuẩn. – AlphaXerion

+1

apple clang7.0 với libC++ cũng hoạt động tốt. –

Các vấn đề liên quan