Я испытал ряд случайных сбоев с использованием класса MFC CFileDialog, поэтому я взглянул на их пример кода из эта страница которая гласит следующее;
#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++;
}
}
От мое чтение об этом, заявление fileName.ReleaseBuffer();
делает память, указанную в буферной переменной p
недопустимый, так что оставшийся код подвержен нарушениям памяти. В то же время я бы также предположил, что Microsoft проверила бы такие примеры до их публикации. Я что-то упускаю здесь очевидное? Есть ли какая-либо причина для использования CString
здесь над простым new
с последующим delete
после того, как буфер больше не требуется?
Пример кода не является официальной документацией. Этот образец неверен. документация правильно:
Адрес, возвращаемый
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*
вместо этого, который почти каждый тип строки предоставляет с помощью функции-члена.
Обратите внимание, что в примере кода есть другие ошибки, которые не были явно учтены в этом ответе (например, несоответствие типов символов, как описано в другом ответ).
* Реализация C ++, которая получает список выбранных файлов, может быть найдена в этом ответ.
Вы можете заметить разницу между спецификацией и реализацией. Код выше работает, потому что CString
реализация позволяет это, хотя CString
спецификация запрещает это.
И чтобы подчеркнуть качество примера: он смешивает TCHAR
а также wchar_t
, В tprintf("%s", start)
строка start
должен быть TCHAR*
но пример использует wchar_t* start