“error C2712: 無法在要求對象展開的函數中使用__try”解決方案

前段時間寫了一篇關於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

c++異常捕獲及異常處理try-throw-catch

https://blog.csdn.net/ShiQW5696/article/details/80283205

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章