我使用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
?
答案 0 :(得分:3)
示例代码不是正式文档。这个样本是错误的。 documentation是对的:
调用
GetBuffer
后,ReleaseBuffer
返回的地址可能无效,因为其他CSimpleStringT
操作可能会导致CSimpleStringT
缓冲区重新分配。
该示例使用CString
(超过原始指针和手动内存管理)进行自动内存管理和异常安全。后者在手动内存管理方面要困难得多(尽管这个样本也没有正确的安全性)。
如果要修复示例代码以遵守合同,则需要进行以下更改: *
wchar_t* pBufEnd = p + FILE_LIST_BUFFER_SIZE - 2;
替换为const wchar_t* pBufEnd = fileName.GetString() + FILE_LIST_BUFFER_SIZE - 2;
。wchar_t* start = p;
替换为const wchar_t* start = fileName.GetString();
p
,并初始化为const wchar_t* current = fileName.GetString();
。)这是一个常见的错误。每当开发人员认为他们需要char*
种类时,他们就会忽略他们需要const char*
,这几乎每种字符串类型都通过成员函数提供。
<小时/> 请注意,示例代码中还有其他错误,这些错误未在此答案中明确说明(如另一个answer中解释的字符类型不匹配)。
<小时/> * 可以在此answer中找到检索所选文件列表的C ++实现。
答案 1 :(得分:2)
您可能会注意到规范和实现之间的差异。上面的代码是有效的,因为CString
实现允许它,即使CString
规范禁止它。
并突出显示示例的质量:它混合了TCHAR
和wchar_t
。在tprintf("%s", start)
中,字符串start
必须是TCHAR*
,但该示例使用wchar_t* start