2013-06-20 101 views
3

Andrei Alexandrescu在最後的C++ and Beyond regarding systematic error handling舉行了一次演講。 我喜歡Expected模板模式並將其調整爲Visual Studio 2010,因爲編譯器目前不支持擴展聯合。所以我寫了一個UnitTest來檢查一切正常。然後我發現我想檢查分片異常的檢測是否有效。但事實並非如此。是否有可能檢測到按值捕獲異常切片?

我不想讓我試着減少它點到這裏粘貼完整代碼:

#include <iostream> 
#include <string> 
#include <exception> 
#include <typeinfo> 

class MyException : public std::exception 
{ 
public: 
    MyException() 
    : std::exception() 
    {} 
    virtual const char* what() const { return "I come from MyException"; } 
}; 

void hereHappensTheFailure() 
{ 
throw MyException(); 
} 

template <class E> 
void detector(const E& exception) 
{ 
    if (typeid(exception) != typeid(E)) 
    { 
    std::cout << "Exception was sliced" << std::endl; 
    } 
    else 
    { 
    std::cout << "Exception was not sliced" << std::endl; 
    } 
} 

int main() 
{ 
    try 
    { 
    hereHappensTheFailure(); 
    } 
    catch (std::exception ex) // intentionally catch by value to provoke the problem 
    { 
    detector(ex); 
    } 

    return 0; 
} 

但沒有檢測到切片。所以我在測試中遇到了錯誤,這是不是VS2010的工作原理,或者模式最終不起作用? (剛剛編輯,因爲gcc 4.7.2上ideone不喜歡) 非常感謝提前!

+2

你試圖做的事是非法的:'std :: exception'是抽象的,因此你不能切片。即使那樣,一旦你切割了一個物體,除非你有某種參考,否則通常不可能知道其來源。 –

+0

@NathanErnst - 'std :: exception'不是抽象的。 –

+0

@PeteBecker,我的不好。我忘了沒有辦法指定什麼'()'沒有繼承就返回。 –

回答

4

您的邏輯錯誤。切片將異常從MyException轉換爲std :: exception。既然你讓模板自動檢測類型,它會選擇與參數相同的類型 - 它保證是相同的。

這樣調用它來代替:

detector<MyException>(ex); 
+0

不應該拋出一個關於非法從'std :: exception'轉換爲'MyException'的錯誤嗎? – soon

+0

@soon,我不確定你指的是什麼演員? –

+0

您將'E'指定爲'MyException',但傳遞'std :: exception'對象。所以,我們從'std :: exception'轉換爲'MyException',但是我沒有看到它的任何允許的構造函數。我錯過了什麼嗎? – soon

0

我想,只有這樣,才能做到這一點是使用運行時多態性例外:虛函數添加到您的異常類,可能只是返回這個指針,您將能夠區分拼接對象和未拼接對象。就像這樣:

class B; 
class A { 
    virtual B* toB() { return NULL; } 
}; 
class B { 
    B* toB() { return this; } 
}; 

之後,你可以在任何一個做的物體可能是B對象:

class A* foo = bar(); 
class B* fooB = foo->toB(); 
if(fooB) { 
    //whatever 
} 

長,因爲你沒有在你的類中的任何虛函數, C++實際上禁止你注意拼接,因爲它斷言對象中不存在虛擬函數表指針,以確保與C-structs的兼容性。但是需要指針來區分這兩種情況。

但是,請注意,只要不使用'new'創建異常對象,我不確定這是否會起作用。如果您的異常被複制到基類類型的變量中,則生成的對象肯定是該基類的類型,而不是它所創建的派生類型。但是'拋出新的MyException()'應該可以工作。

相關問題