前段時間寫了一篇關于C++異常捕獲及異常處理的文章:
c++異常捕獲及異常處理try-throw-catch
嚴格的來說,那不算是一篇完整的文章,更多的是提出我的疑惑。順便總結了一下網友關于C++異常捕獲及異常處理給出的精煉的示例。
至今,上文提到的疑惑本菜鳥都沒有完全解開。
于是,我就選擇了用 __try __except 來捕獲及處理異常。經過測試,我想捕獲的異常用 __try __except 都捕獲到了,相當開心。
但是,今天在用 __try __except 的時候蹦出來一個讓我既苦惱又興奮的錯誤:
error C2712: 無法在要求對象展開的函數中使用__try
本能的打開百度,輸入錯誤提示,一頓查找,并沒有找到很好了解的解釋。于是我求救 google ,終于找到了我能很容易了解的解釋。(哎,國小國文沒學好就是吃虧)
首先,我們來看幾個會報C2712錯誤的示例:
#include <string>
inline std::string foo() { return "abc"; }
inline int foo2() { return 612; }
class MyClass
{
public:
MyClass() { m_val = 0; }
MyClass(int param) { m_val = param; }
~MyClass();
int GetVal() { return m_val; }
private:
int m_val;
};
void TestTryExcept_1()
{
using namespace std;
string str = "666"; // string 是一個類,銷毀對象時會調用析構函數,是以會報錯
__try
{
// Do anything
}
__except (EXCEPTION_EXECUTE_HANDLE)
{
printf_s("__except\n");
}
// string str; // 無論放在函數裡的什麼位置都會導緻 C2712 錯誤
}
void TestTryExcept_2()
{
using namespace std;
// foo()傳回的是臨時的string對象,
// 也就是說,調用foo()時,會生成一個臨時的string變量存放傳回的資料
// 本質上和TestTryExcept_1()是一樣的
foo();
// 和 TestTryExcept_1() 一樣使用了 string 類
// string retStr = foo();
__try
{
// Do anything
}
__except (EXCEPTION_EXECUTE_HANDLE)
{
printf_s("__except\n");
}
}
void TestTryExcept_3()
{
// 使用了自己定義的類也會報錯,因為銷毀對象時同樣會調用析構
MyClass ObjA(612);
int ret = ObjA.GetVal();
__try
{
printf_s("__try: %d\n", ret);
}
__except (EXCEPTION_EXECUTE_HANDLE)
{
printf_s("__except\n");
}
}
int _tmain(int argc, _TCHAR* argv[])
{
TestTryExcept_1();
TestTryExcept_2();
TestTryExcept_3();
return 0;
}
上述代碼在編譯的時候會報C2712錯誤,原因在代碼注釋中簡單注明了。
其實原因就是:
在使用 __try __except 的函數中任何位置(測試的幾個位置都會報錯,如有描述錯誤請告知)建立了類對象就會導緻C2712編譯錯誤。
///
msdn上給出的描述和解決方案
Compiler Error C2712
cannot use __try in functions that require object unwinding
When you use /EHsc, a function with structured exception handling cannot have objects that require unwinding (destruction).
Possible solutions:
- Move code that requires SEH to another function
- Rewrite functions that use SEH to avoid the use of local variables and parameters that have destructors. Do not use SEH in constructors or destructors
- Compile without /EHsc
Error C2712 can also occur if you call a method declared by using the __event keyword. Because the event might be used in a multithreaded environment, the compiler generates code that prevents manipulation of the underlying event object, and then encloses the generated code in an SEH try-finally statement. Consequently, error C2712 will occur if you call the event method and pass by value an argument whose type has a destructor. One solution in this case is to pass the argument as a constant reference.
//
我們來将上面三個函數和 main 修改一下:
void TestTryExcept_1()
{
using namespace std;
string str = "666";
printf_s("TestTryExcept_1: %s\n", str.c_str());
}
void TestTryExcept_2()
{
using namespace std;
printf_s("TestTryExcept_2: %s\n", foo());
}
void TestTryExcept_3()
{
MyClass ObjA(612);
int ret = ObjA.GetVal();
printf_s("TestTryExcept_3: %d\n", ret);
}
int _tmain(int argc, _TCHAR* argv[])
{
// 類對象的建立 不能和__try__except在同一個函數中
//using namespace std;
//string str = "main, string object";
//printf_s("%s\n", str);
__try
{
TestTryExcept_1();
TestTryExcept_2();
TestTryExcept_3();
}
__except (EXCEPTION_EXECUTE_HANDLE)
{
printf_s("__except\n");
}
getchar();
return 0;
}
大家可以看到,上述修改後的代碼還存在一個問題,就是在 main 中使用了__try __except 後,就無法建立類對象,也就是像 string 這樣的類就無法使用了,要不然就會報錯。
是以我們再修改一下,把 main 拆成兩個函數:
void TestTryExcept_all()
{
__try
{
TestTryExcept_1();
TestTryExcept_2();
TestTryExcept_3();
}
__except (EXCEPTION_EXECUTE_HANDLE)
{
printf_s("__except\n");
}
}
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
string str = "main, string object";
printf_s("%s\n", str);
TestTryExcept_all();
getchar();
return 0;
}
這樣,所有問題就解決啦。
純手打,如果有什麼問題,歡迎各位大佬指出。
好了,我給大佬遞茶去了。。。
聲明:上述代碼未包含所有需要的頭檔案,請大家自行腦補。
參考:
Compiler Error C2712
very simple code, and getting error C2712, could not understand why
版權聲明
如需轉載請注明來源和作者,謝謝!!
本文連結:https://blog.csdn.net/ShiQW5696/article/details/80664749