2013-03-09 46 views
6

C++ Chuẩn khẳng định sau đây về việc thực hiện các std::call_once với chức năng mà ném ngoại lệ (§30.4.4.2/2):Ném một ngoại lệ từ std :: call_once

2/Tác dụng: An thực hiện call_once mà không gọi func của nó là một thực thi thụ động. Việc thực thi call_once gọi hàm func của nó là một thực thi hoạt động. Một thực thi hoạt động sẽ gọi INVOKE (DECAY_- COPY (std :: forward (func)), DECAY_COPY (std :: forward (args)) ...). Nếu một cuộc gọi đến func ném một ngoại lệ thì việc thực hiện là ngoại lệ, nếu không nó sẽ trở lại. Một thực thi đặc biệt sẽ truyền bá ngoại lệ cho người gọi call_once. Trong số tất cả các lệnh gọi hàm call_once đối với bất kỳ once_flag cụ thể nào: tối đa là một lệnh thực thi trả về; nếu có một thực thi trả về, nó sẽ là thực thi hoạt động cuối cùng; và chỉ có các thực thi thụ động nếu có thực thi trả về. [Lưu ý: thực thi thụ động cho phép các luồng khác quan sát một cách đáng tin cậy các kết quả được tạo ra bởi thực thi trả về trước đó. - cuối note]

Tôi đang sử dụng Visual Studio 2012 và chạy đoạn mã sau:

void f(){ 
    throw std::exception("Catch me!"); 
} 

int main(int argc, char* argv[]){ 
    once_flag flag; 
    try{ 
     call_once(flag, f); 
    } catch(const std::exception& e){ 
     cout << e.what() << endl; 
    } 
    return 0; 
} 

kết quả của tôi là: mã trong khối catch chạy và in thông điệp, nhưng khi chương trình tồn tại tôi nhận được một cuộc gọi đến abort() và được thông báo sau in để cout:

... \ mutex.c (38) mutex bị phá hủy trong khi bận rộn

Điều này có nghĩa vụ phải xảy ra không?

+2

Không, đó là lỗi, chương trình sẽ hoạt động tốt (mặc dù bạn đang sử dụng hàm tạo không chuẩn cho 'std :: exception', trong ISO C++ bạn chỉ có thể mặc định xây dựng' std :: exception', nguyên nhân Các vấn đề về tính di động thường xuyên khi người dùng MSVC kiểm tra lỗi có nghĩa là biên dịch trên các triển khai khác) –

Trả lời

7

Điều này có nghĩa vụ phải xảy ra không?

Không, không thực sự. Đây là lỗi lỗi.

Tuy nhiên, hãy chú ý một thực tế rằng VC11 không phải là một mình về vấn đề này:

  • Intel ICC 13.0.1 gọi std::terminate() như thể ngoại trừ của bạn đã không được xử lý (xem live example);
  • GCC 4.8.0 beta có thể hoạt động tương tự, nhưng nó không hiển thị bất kỳ đầu ra nào, nó chỉ nuốt ngoại lệ và âm thầm chấm dứt chương trình (xem live example). [UPDATE: Lỗi này dường như không thể lặp lại trong các môi trường khác và có khả năng là một vấn đề với cấu hình trên liveworkspace.org chỉ]

GCC 4.7.2 và Clang 3.2, mặt khác , cư xử đúng.

Nhân tiện, cần lưu ý rằng tiêu chuẩn C++ (Đoạn 18.8.1) quy định rằng std::exceptiononly has a default constructor and a copy constructor. Hàm khởi tạo bạn đang sử dụng có nhiều khả năng là phần mở rộng MS không di động.

Bạn có thể xem xét sử dụng std::logic_error thay vào đó, có nguồn gốc từ std::exception và hỗ trợ một hàm tạo chấp nhận một chuỗi.

+1

Cảm ơn bạn, tôi không biết std :: ngoại lệ chỉ có một hàm tạo mặc định và sao chép, tôi thực sự đang sử dụng các ngoại lệ tùy chỉnh trong mã ban đầu. Tôi sẽ không ném ngoại lệ ra khỏi call_once bây giờ, cảm ơn cho làm rõ. –

+4

Nó cũng đáng chú ý khi 'call_once' trả về với một ngoại lệ, nó không được coi là hài lòng. I E. lần sau khi 'call_once' được thực hiện,' f' sẽ được thử lại. Và cứ thế, cho đến khi 'f' trả về mà không ném một ngoại lệ. –

+0

@HowardHinnant: Quan sát tốt, cảm ơn bạn đã đề cập đến điều đó. –