代码分析 C26408——替换InitInstance中的m_pszHelpFilePath变量

Code analysis C26408 — Replacing the m_pszHelpFilePath variable in InitInstance

在我的应用程序的 InitInstance 函数中,我有以下代码来重写 CHM 帮助文档的位置:

CString strHelp = GetProgramPath();
strHelp += _T("MeetSchedAssist.CHM");
free((void*)m_pszHelpFilePath);
m_pszHelpFilePath = _tcsdup(strHelp);

一切正常,但它给了我一个代码分析警告:

C26408 Avoid malloc() and free(), prefer the nothrow version of new with delete (r.10).


当您查看 m_pszHelpFilePath 的官方文档时,它确实声明:

If you assign a value to m_pszHelpFilePath, it must be dynamically allocated on the heap. The CWinApp destructor calls free( ) with this pointer. You many want to use the _tcsdup( ) run-time library function to do the allocating. Also, free the memory associated with the current pointer before assigning a new value.

是否可以重写此代码以避免代码分析警告,或者我必须添加一个 __pragma

从技术上讲,您可以利用 new / delete 在 Visual C++ 中默认映射到通常的 malloc/free 的事实,然后继续并更换。可移植性不会受到太大影响,因为 MFC 无论如何都不可移植。当然你可以使用 unique_ptr<TCHAR[]> 而不是直接 new / delete,像这样:

CString strHelp = GetProgramPath();
strHelp += _T("MeetSchedAssist.CHM");
std::unique_ptr<TCHAR[]> str_old(m_pszHelpFilePath);
auto str_new = std::make_unique<TCHAR[]>(strHelp.GetLength() + 1);
_tcscpy_s(str_new.get(), strHelp.GetLength() + 1, strHelp.GetString());
m_pszHelpFilePath = str_new.release();
str_old.reset();

为了替换 new 运算符的稳健性,并且为了最少意外原则,您应该保留 free / strdup.

如果您替换其中多个 CWinApp 字符串,建议为它们编写一个函数,以便只有一个地方带有 free / strdup 并抑制警告。

您可以(应该?)使用智能指针来包装您重新分配的 m_pszHelpFilePath 缓冲区。然而,虽然这不是微不足道的,但可以毫不费力地完成。

首先,在您的派生应用程序中声明一个适当的 std::unique_ptr 成员 class:

class MyApp : public CWinApp // Presumably
{
// Add this member...
public:
    std::unique_ptr<TCHAR[]> spHelpPath;
// ...
};

然后,您将需要修改构建和分配帮助路径的代码,如下所示(我已将您的 C 风格转换为可以说是更好的 C++ 转换):

// First three (almost) lines as before ...
CString strHelp = GetProgramPath();
strHelp += _T("MeetSchedAssist.CHM");
free(const_cast<TCHAR *>(m_pszHelpFilePath));

// Next, allocate the shared pointer data and copy the string...
size_t strSize = static_cast<size_t>(strHelp.GetLength() + 1); 
spHelpPath std::make_unique<TCHAR[]>(strSize);
_tcscpy_s(spHelpPath.get(), strHelp.GetString()); // Use the "_s" 'safe' version!

// Now, we can use the embedded raw pointer for m_pszHelpFilePath ...
m_pszHelpFilePath = spHelpPath.get();

到目前为止,还不错。当您的应用程序对象被销毁时,智能指针中分配的数据将自动释放,并且代码分析警告应该消失。但是,我们需要进行最后一项修改,以防止 MFC 框架尝试释放我们分配的 m_pszHelpFilePath 指针。这可以通过在 MyApp class 覆盖 ExitInstance:

中将其设置为 nullptr 来完成
int MyApp::ExitInstance()
{
    // <your other exit-time code>
    m_pszHelpFilePath = nullptr;
    return CWinApp::ExitInstance(); // Call base class
}

但是,这可能看起来无事生非,正如其他人所说,您可能有理由简单地取消警告。