2010-03-19 22 views
7

Có một số bài báo kết luận "không bao giờ ném một ngoại lệ từ một destructor", và "std :: uncaught_exception() là không hữu ích", ví dụ:sử dụng quyền của std :: uncaught_exception trong một destructor

Nhưng có vẻ như tôi không nhận được điểm. Vì vậy, tôi đã viết một ví dụ thử nghiệm nhỏ (xem bên dưới).

Vì mọi thứ đều ổn với ví dụ kiểm tra, tôi sẽ đánh giá cao một số nhận xét về những gì có thể sai với nó?

kiểm tra kết quả:

./main

 
    Foo::~Foo(): caught exception - but have pending exception - ignoring 
    int main(int, char**): caught exception: from int Foo::bar(int) 

./main 1

 
    Foo::~Foo(): caught exception - but *no* exception is pending - rethrowing 
    int main(int, char**): caught exception: from Foo::~Foo() 

dụ:

// file main.cpp 
// build with e.g. "make main" 
// tested successfully on Ubuntu-Karmic with g++ v4.4.1 
#include <iostream> 

class Foo { 
    public: 

    int bar(int i) { 
    if (0 == i) 
     throw(std::string("from ") + __PRETTY_FUNCTION__); 
    else 
     return i+1; 
    } 

    ~Foo() { 
    bool exc_pending=std::uncaught_exception(); 
    try { 
     bar(0); 
    } catch (const std::string &e) { 
     // ensure that no new exception has been created in the meantime 
     if (std::uncaught_exception()) exc_pending = true; 

     if (exc_pending) { 
     std::cerr << __PRETTY_FUNCTION__ 
        << ": caught exception - but have pending exception - ignoring" 
        << std::endl; 
     } else { 
     std::cerr << __PRETTY_FUNCTION__ 
        << ": caught exception - but *no* exception is pending - rethrowing" 
        << std::endl; 
     throw(std::string("from ") + __PRETTY_FUNCTION__); 
     } 
    } 
    } 

}; 

int main(int argc, char** argv) { 
    try { 
    Foo f; 
    // will throw an exception in Foo::bar() if no arguments given. Otherwise 
    // an exception from Foo::~Foo() is thrown. 
    f.bar(argc-1); 
    } catch (const std::string &e) { 
    std::cerr << __PRETTY_FUNCTION__ << ": caught exception: " << e << std::endl; 
    } 
    return 0; 
} 

THÊM : Nói cách khác: bất chấp cảnh báo trong một số bài báo, nó hoạt động như mong đợi - vậy điều gì có thể sai với nó?

+2

Câu hỏi của bạn là gì? Dường như bạn đang quan sát hành vi mong đợi của một cơ chế mà bạn không nên sử dụng. Bạn đang cân nhắc việc sử dụng nó bên ngoài ngữ cảnh thử nghiệm/thử nghiệm và tại sao? – Potatoswatter

+0

@Potatoswatter: câu hỏi đặt ra là: 'mặc dù có cảnh báo trong một số bài báo nó hoạt động như mong đợi - vì vậy điều gì có thể sai với nó?' –

+0

Không, nhưng đó không phải là những gì bạn nói, và không thể biết những gì được mong đợi, thích hợp hoặc an toàn trong ngữ cảnh của bạn mà không cần thêm thông tin. Con đường an toàn, như Herb Sutter và nhiều người khác sẽ nói với bạn, không phải là để ném từ một destructor ở nơi đầu tiên. – Potatoswatter

Trả lời

5

Không có gì sai về mặt kỹ thuật với mã của bạn. Nó hoàn toàn an toàn trong đó bạn sẽ không bao giờ vô tình chấm dứt bởi vì bạn đã ném một ngoại lệ khi nó không an toàn. Vấn đề là nó cũng không hữu ích, ở chỗ nó đôi khi cũng sẽ không ném một ngoại lệ khi nó được an toàn. Tài liệu của destructor của bạn về cơ bản phải nói "điều này có thể hoặc không thể ném một ngoại lệ."

Nếu thỉnh thoảng sẽ không ném ngoại lệ, bạn cũng có thể không bao giờ ném ngoại lệ. Bằng cách đó, bạn ít nhất là nhất quán.

6

Herb Sutter đề cập đến một vấn đề khác. Anh ấy nói về:

try 
{ 
} 
catch (...) 
{ 
    try 
    { 
     // here, std::uncaught_exception() will return true 
     // but it is still safe to throw an exception because 
     // we have opened a new try block 
    } 
    catch (...) 
    { 
    } 
} 

Vì vậy, vấn đề là nếu std::uncaught_exception() trả về true bạn không biết chắc chắn liệu bạn có thể ném một cách an toàn một ngoại lệ hay không. Bạn cuối cùng phải tránh ném một ngoại lệ khi std::uncaught_exception() trả về true chỉ để được an toàn.

+0

@Samuel: '... đề cập đến một vấn đề khác ...' Đó là điều tôi cũng nghĩ. Và - vì tôi không ném một ngoại lệ khi uncaught_exception() trả về sự thật - bạn có tin rằng cách tiếp cận của tôi là an toàn không? –

+0

Điều đó thực sự không đúng. Ngoại lệ của bạn bị bắt tại thời điểm đó. Bạn nên đã đặt thử/bắt trong một destructor, đó là invoked trong khi stack unwinding (do một ngoại lệ hoạt động). Trong tình huống đó, một ngoại lệ * là * chủ động mở ngăn xếp, nhưng bạn đang ở ngay sau đó bên trong một khối try/catch nơi bạn * có thể * ném một ngoại lệ. – dascandy

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