此Microsoft CFileDialog示例是否会导致潜在的内存违规

时间:2017-02-02 13:17:09

标签: c++ mfc cfiledialog

我使用MFC CFileDialog类经历了一些随机崩溃,因此我查看了this page中的示例代码,其内容如下:

#define MAX_CFileDialog_FILE_COUNT 99
#define FILE_LIST_BUFFER_SIZE ((MAX_CFileDialog_FILE_COUNT * (MAX_PATH + 1)) + 1)

CString fileName;
wchar_t* p = fileName.GetBuffer( FILE_LIST_BUFFER_SIZE );
CFileDialog dlgFile(TRUE);
OPENFILENAME& ofn = dlgFile.GetOFN( );
ofn.Flags |= OFN_ALLOWMULTISELECT;
ofn.lpstrFile = p;
ofn.nMaxFile = FILE_LIST_BUFFER_SIZE;

dlgFile.DoModal();
fileName.ReleaseBuffer();  

wchar_t* pBufEnd = p + FILE_LIST_BUFFER_SIZE - 2;  
wchar_t* start = p;
while( ( p < pBufEnd ) && ( *p ) )
  p++;
if( p > start )
{
  _tprintf(_T("Path to folder where files were selected:  %s\r\n\r\n"), start );
  p++;

  int fileCount = 1;
  while( ( p < pBufEnd ) && ( *p ) )
  {
    start = p;
    while( ( p < pBufEnd ) && ( *p ) )
      p++;
    if( p > start )
      _tprintf(_T("%2d. %s\r\n"), fileCount, start );
    p++;
    fileCount++;
  }
}

通过它my reading,语句fileName.ReleaseBuffer();使缓冲区变量p中指向的内存无效,这样剩下的代码就容易出现内存冲突。与此同时,我还假设微软会在发布之前检查这些例子。我错过了一些明显的东西吗?在不再需要缓冲区之后,是否有理由在CString之后使用new后跟delete

2 个答案:

答案 0 :(得分:3)

示例代码不是正式文档。这个样本是错误的。 documentation是对的:

  

调用GetBuffer后,ReleaseBuffer返回的地址可能无效,因为其他CSimpleStringT操作可能会导致CSimpleStringT缓冲区重新分配。

该示例使用CString(超过原始指针和手动内存管理)进行自动内存管理和异常安全。后者在手动内存管理方面要困难得多(尽管这个样本也没有正确的安全性)。

如果要修复示例代码以遵守合同,则需要进行以下更改: *

  1. wchar_t* pBufEnd = p + FILE_LIST_BUFFER_SIZE - 2;替换为const wchar_t* pBufEnd = fileName.GetString() + FILE_LIST_BUFFER_SIZE - 2;
  2. wchar_t* start = p;替换为const wchar_t* start = fileName.GetString();
  3. 在对话框调用后,使用新变量替换代码中所有剩余的p,并初始化为const wchar_t* current = fileName.GetString();。)
  4. 这是一个常见的错误。每当开发人员认为他们需要char*种类时,他们就会忽略他们需要const char*,这几乎每种字符串类型都通过成员函数提供。

    <小时/> 请注意,示例代码中还有其他错误,这些错误未在此答案中明确说明(如另一个answer中解释的字符类型不匹配)。

    <小时/> * 可以在此answer中找到检索所选文件列表的C ++实现。

答案 1 :(得分:2)

您可能会注意到规范和实现之间的差异。上面的代码是有效的,因为CString实现允许它,即使CString规范禁止它。

并突出显示示例的质量:它混合了TCHARwchar_t。在tprintf("%s", start)中,字符串start必须是TCHAR*,但该示例使用wchar_t* start