C++Builder 12.2 错误:“无法在与 SEH '__try' 相同的函数中使用 C++ 'try'”

问题描述 投票:0回答:1

计算机崩溃并在新计算机上重新安装 C++Builder 12.2 后,某些代码无法再编译。例如:

void __fastcall TSynCustomExporter::CopyToClipboardFormat(UINT AFormat)                      
    ...                                                                                          
    try // line 206
    {                                                                                        
        PtrData = ((Byte*) GlobalLock((HGLOBAL) hData));                                       
        if(ASSIGNED(PtrData))                                                                  
        {                                                                                      
            try // line 211
            {                                                                                    
                fBuffer->Position = 0;                                                             
                fBuffer->Read((void**)PtrData, (TNativeCount) (hDataSize - 1)); // trailing #0     
            }                                                                                    
            __finally                                                                            
            {                                                                                    
                GlobalUnlock((HGLOBAL) hData);                                                     
            }                                                                                    
            Clipboard()->SetAsHandle(AFormat, hData);                                            
        }                                                                                      
        else                                                                                   
            Abort();                                                                               
    }                                                                                        
    catch(...)                                                                               
    {                                                                                        
        GlobalFree((HGLOBAL) hData);                                                           
        OutOfMemoryError();                                                                    
    }         

错误信息是:

[bcc64x Error] SynEditExport.cpp(206): cannot use C++ 'try' in the same function as SEH '__try'
[bcc64x Hint] SynEditExport.cpp(211): conflicting '__try' here

其他编译器对此类错误消息有解释,但 C++Builder 有自己特殊的

__finally
扩展来重现 Delphi 行为。

我发现有一个补丁可能会导致新行为:

RSS-698:尝试在win64x下捕获最终错误

不幸的是我无法登录。

我想了解更多有关此错误消息的背景。如果补丁真的要对此负责,我想知道该补丁是否不会产生比修复错误更多的错误。


更新:

感谢您提出解决问题的建议。但是,为了简单起见,我没有充分解释其背景。

代码示例是使用 Delphi2CB 工具自动转换以下 Delphi 代码的结果:

procedure TSynCustomExporter.CopyToClipboardFormat(AFormat: UINT);
  ...
  try
    PtrData := GlobalLock(hData);
    if Assigned(PtrData) then
    begin
      try
        fBuffer.Position := 0;
        fBuffer.Read(PtrData^, hDataSize - 1); // trailing #0
      finally
        GlobalUnlock(hData);
      end;
      Clipboard.SetAsHandle(AFormat, hData);
    end
    else
      Abort;
  except
    GlobalFree(hData);
    OutOfMemoryError;
  end;

这种转换并不复杂,每个用户都可以立即理解。

示例代码取自 C++ 版本的 SynEdit 组件,该错误现在经常发生。针对这种情况构建特殊结构并不能解决其他情况。使用

scope_exit
将是一个通用解决方案,但不直观。

正如我一开始所说的,几周前这个问题还不存在。我不明白为什么代码突然停止工作。

c++ delphi try-catch c++builder finally
1个回答
0
投票

我想将 Remy Lebeau 的最后一个答案标记为最佳答案,但找不到“答案左侧的绿色勾勒勾号”,所以我在这里重复一遍:

Clang 根本不支持在同一个函数中将 C++ try/catch 与 SEH __try/__ except/__finally 混合使用,而且从来不支持。 Borland 的 bcc32 编译器始终允许将其作为编译器扩展。这是有记录的: https://docwiki.embarcadero.com/RADStudio/en/Stricter_C%2B%2B_Compilers_(Clang-enhanced_C%2B%2B_Compilers)#Structural_Syntax

我补充一下:在C++Builder Athens补丁之前进行过这样的混合编译,但现在不再进行了。 Synedit 的现代 C++ 编译器版本的代码已通过使用代码防护进行更正,类似于 Pepijn Kramer 的建议。

void __fastcall TSynCustomExporter::CopyToClipboardFormat(UINT AFormat)
{
  ...
        try
        {
            PtrData = ((Byte*) GlobalLock((HGLOBAL) hData));
            if(ASSIGNED(PtrData))
            {
                {
                    auto olsLambda = onLeavingScope([&] 
                    {
                        GlobalUnlock((HGLOBAL) hData);
                    });
                    fBuffer->Position = 0;
                    fBuffer->Read((void**)PtrData, (TNativeCount) (hDataSize - 1)); // trailing #0
                }
                Clipboard()->SetAsHandle(AFormat, hData);
            }
            else
            Abort();
        }
        catch(...)
        {
            GlobalFree((HGLOBAL) hData);
            OutOfMemoryError();
        }
}

Delphi2CB 已更正,因此仅在不存在冲突时才使用 try...__finally

© www.soinside.com 2019 - 2024. All rights reserved.