代码分析 C26408 — 替换 InitInstance 中的 m_pszHelpFilePath 变量
Posted
技术标签:
【中文标题】代码分析 C26408 — 替换 InitInstance 中的 m_pszHelpFilePath 变量【英文标题】:Code analysis C26408 — Replacing the m_pszHelpFilePath variable in InitInstance 【发布时间】:2021-11-01 14:44:04 【问题描述】:在我的应用程序的InitInstance
函数中,我有以下代码来重写 CHM 帮助文档的位置:
CString strHelp = GetProgramPath();
strHelp += _T("MeetSchedAssist.CHM");
free((void*)m_pszHelpFilePath);
m_pszHelpFilePath = _tcsdup(strHelp);
一切正常,但它给了我一个代码分析警告:
C26408 避免使用
malloc()
和free()
,更喜欢nothrow
版本的new
和delete
(r.10)。
当您查看m_pszHelpFilePath
的官方文档时,它确实声明:
如果你给
m_pszHelpFilePath
赋值,它必须在堆上动态分配。CWinApp
析构函数使用此指针调用free( )
。许多人想使用_tcsdup( )
运行时库函数来进行分配。此外,在分配新值之前释放与当前指针关联的内存。
是否可以重写此代码以避免代码分析警告,或者我必须添加__pragma
?
【问题讨论】:
【参考方案1】:您可以(应该?)使用智能指针来包装您重新分配的 m_pszHelpFilePath
缓冲区。不过,这虽然不是小事,但也可以不费吹灰之力地完成。
首先,在您的派生应用程序类中声明一个适当的std::unique_ptr
成员:
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
指针。这可以通过在ExitInstance
的MyApp
类覆盖中将其设置为nullptr
来完成:
int MyApp::ExitInstance()
// <your other exit-time code>
m_pszHelpFilePath = nullptr;
return CWinApp::ExitInstance(); // Call base class
但是,这可能看起来无所事事,正如其他人所说,您可能有理由简单地取消警告。
【讨论】:
感谢您的回答。我觉得我只会让它被压制。但这都是有用的信息...有趣的是您使用了const_cast
... :) 为什么我说以后可能会清楚!
@AndrewTruckle 没有。没有演员,你会得到一个错误:error C2664: 'void free(void *)': cannot convert argument 1 from 'LPCTSTR' to 'void * '
@AndrewTruckle 好吧,这是代码分析器中的一条愚蠢规则。这正是const_cast
的用途!
您可以在单个编译指示中抑制多个警告:逗号分隔列表。
抱歉 - 空格 分隔列表。 docs【参考方案2】:
从技术上讲,您可以利用 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
并带有隐藏的警告。
【讨论】:
我只有这一个实例。但是,如果我将其更改为delete
,那会不会触发另一个关于避免使用new
或delete
的分析警告?或者,您是说可以拨打operator delete (m_pszHelpFilePath, std::nothrow);
。 ?
@AndrewTruckle,我添加了一个示例,您可以如何使用unique_ptr
而不是new
/delete
(没试过,写在这里)。但这只是技术上部分的解释,我认为你不应该遵循警告中的建议。
好吧,我会简单地用__pragma
压制。以上是关于代码分析 C26408 — 替换 InitInstance 中的 m_pszHelpFilePath 变量的主要内容,如果未能解决你的问题,请参考以下文章