2016-02-11 37 views
0

我試圖擴展std::packaged_task來處理SEH異常,但我不能讓它編譯。C++ 11如何擴展一個類模板,如std :: packaged_task

以下不會編譯:

#include <stdio.h> 
#include <functional> 
#include <future> 
#include <windows.h> 

template<class RET, class... ARGS> 
class SafePackagedTask : public std::packaged_task<RET(ARGS...)> 
{ 
public: 
    template<class F> 
    explicit SafePackagedTask(F && f) 
    : std::packaged_task*(std::forward<F>(f)) 
    { 
    } 

    void operator()(ARGS... args) 
    { 
    __try 
    { 
     std::packaged_task*(std::forward<ARGS>(args)); 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     printf("SEH Exception 0x%08lX in SafePackagedTask!\n", GetExceptionCode()); 
    } 
    } 

}; 

int main() 
{ 
    SafePackagedTask<int()> task([] { 
     //int *a = nullptr; *a = 1; // generate SEH 
     return 1; 
    }); 
    std::future<int> fut = task.get_future(); 
    task(); 
    int rc = fut.get(); 
    printf("result: %d\n", rc); 
} 

的錯誤是:

source_file.cpp(9): error C2091: function returns function 
source_file.cpp(37): note: see reference to class template instantiation 'SafePackagedTask<int (void)>' being compiled 
source_file.cpp(38): error C2440: 'initializing': cannot convert from 'std::future<_Ret>' to 'std::future<int>' 
     with 
     [ 
      _Ret=int (__cdecl *)(void) 
     ] 
source_file.cpp(38): note: No constructor could take the source type, or constructor overload resolution was ambiguous 

看到它的rextester.com

回答

1

終於搞定了。

#include <stdio.h> 
#include <functional> 
#include <future> 
#include <windows.h> 

template<class RET, class... ARGS> 
class SafePackagedTask; 

template<class RET, class... ARGS> 
class SafePackagedTask<RET(ARGS...)> : public std::packaged_task<RET(ARGS...)> 
{ 
public: 
    template<class F> 
    explicit SafePackagedTask(F && f) 
    : std::packaged_task<RET(ARGS...)>(std::forward<F>(f)) 
    { 
    } 

    void operator()(ARGS... args) 
    { 
    __try 
    { 
     std::packaged_task<RET(ARGS...)>::operator()(std::forward<ARGS>(args)...); 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     printf("SEH Exception 0x%08lX in SafePackagedTask!\n", GetExceptionCode()); 
     // ... print stack trace ... 
    } 
    } 

}; 

int main() 
{ 
    SafePackagedTask<int()> task([] { 
     int *a = nullptr; *a = 1; // generate SEH 
     return 1; 
    }); 
    std::future<int> fut = task.get_future(); 
    try 
    { 
     task(); 
     int rc = fut.get(); 
     printf("result: %d\n", rc); 
    } 
    catch (std::exception& e) 
    { 
     printf("error inside lambda: %s\n", e.what()); 
    } 
    return 0; 
} 

遺憾的是它並沒有做什麼,我想在/EHa模式,因爲在一個future::get()packaged_task其中捕捉一切catch(...),然後重新拋出。永遠不會到達__except處理程序,並且原始堆棧跟蹤丟失。於是,我放棄了這種做法,並換基礎任務本身:

template <typename F> 
struct SafeTaskWrapper : F 
{ 
    SafeTaskWrapper(F&& f) : F(std::move(f)) {} 

    SafeTaskWrapper(SafeTaskWrapper&&) = default; 
    SafeTaskWrapper& operator=(SafeTaskWrapper&&) = default; 

    SafeTaskWrapper(const SafeTaskWrapper&) = default; 
    SafeTaskWrapper& operator=(const SafeTaskWrapper&) = default; 

    void operator()() 
    { 
    __try 
    { 
     F::operator()(); 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     printf("SEH Exception 0x%08lX in lambda!\n", GetExceptionCode()); 
     // ... print stack trace ... 
     throw std::runtime_error("SEH Exception in lambda"); 
    } 
    } 
}; 

template <typename T> 
auto make_safe_task(T&& t) -> SafeTaskWrapper<typename std::decay<T>::type> 
{ 
    return std::move(t); 
} 

int main() 
{ 
    std::packaged_task<int()> task(make_safe_task([] { 
     //int *a = nullptr; *a = 1; // generate SEH 
     return 1; 
    })); 
    std::future<int> fut = task.get_future(); 
    try 
    { 
     task(); 
     int rc = fut.get(); 
     printf("result: %d\n", rc); 
    } 
    catch (std::exception& e) 
    { 
     printf("error inside lambda: %s\n", e.what()); 
    } 
    return 0; 
} 
1

許多std類不打算繼承。一個線索是,如果析構函數不是虛擬的,那麼至少該類不打算多形地使用。

+0

我完全控制我的類的生命週期。非虛擬析構函數不是問題。 – rustyx

+0

@rustyx我有同事誰擴展了其他性病庫類像矢量或地圖,也可行,雖然有點非正統。 –

2

您正試圖解決已解決的問題。
SEH異常可以像常規C++標準異常一樣通過在VC++上設置特定標誌來處理(您明確使用)*

轉至項目 - > C/C++ - >代碼生成 - >設置「啓用C++異常」 「有SEH例外」。

現在你可以捕獲SEH異常,並catch(...)條款:

try{ 

}catch(std::exception& e){} 
catch(...) {/*your code here*} 

其他,應對SEH異常的最好方法是在不首先創建它們。不要試圖超出你的數組邊界,檢查空指針,在需要時使用智能指針,仔細編寫你的類來使用RAII,可能會消除代碼中95%的異常。

*基本上,在Windows上,所有C++異常都是windows SEH的子集,並按照這種方式實現。

+0

我們不使用此設置,因爲我們需要有關SEH例外的更多詳細信息。 RAII和所有這些對於新的開發來說當然都很好,但是我們不得不使用很多遺留代碼。 – rustyx

+0

在catch(...)塊中使用GetExceptionCode()獲取錯誤代碼有什麼問題? –

+0

'錯誤C2707:'_exception_code':內部函數的錯誤上下文。另外,堆棧跟蹤來自ReThrow,而不是原來的位置。 – rustyx