Как использовать дескриптор в WINAPI, когда я реализую свой код С++ с принципом RAII?

Каков наилучший способ использования объекта HANDLE из WINAPI, когда я хочу написать свой код, учитывая принцип RAII в С++

Я пишу следующий код:

bool Uninstall(wstring folder, const bool removeDir = NULL)
{
    //init for run over file in dir by winapi
    unique_ptr<WIN32_FIND_DATA> ffd = make_unique<WIN32_FIND_DATA>();
    HANDLE handle;
    wstring path_for_search = folder + L"\\*"; // for include all the things in path when run over    the files or directories
    //List files
    handle = FindFirstFileW(path_for_search.c_str(), ffd.get());
    // run over files and directories by handle
    do {
        if (wcscmp(ffd->cFileName, L".") != 0 && wcscmp(ffd->cFileName, L"..") != 0) // pass the default '.' and ".." 
        {
            wstring file_or_dir_path = folder + L"\\" + ffd->cFileName; // get the full file or dir path
            if (GetFileAttributes(file_or_dir_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) // check if directory
            {
                Uninstall(file_or_dir_path, false); // recursive call for uninstall the content in the sub dir itself your text
            }
            else
            {
                DeleteFileW(file_or_dir_path.c_str()); // delete the file
            }
        }
    } while (FindNextFile(handle, ffd.get()));
    FindClose(handle);
    delete handle;
    //check if remove the original dir
    if (!removeDir)
    {
        RemoveDirectoryW(folder.c_str());
    }
    return true;
}

Но я не уверен, как реализовать автоматический класс RAII для этого объекта.

Для общего HANDLE, который должен быть передан CloseHandle, вы все еще можете использовать стандартный интеллектуальный указатель, но с пользовательским средством удаления, которое вызывает CloseHandle. Легко переводится на FindFirstFile и FindClose.

Some programmer dude 07.02.2023 23:16

Создайте класс умного указателя, деструктор которого вызывает CloseHandle().

Hans Passant 07.02.2023 23:17

Также обратите внимание, что, поскольку стандарт C++ 17 C++ имеет пространство имен файловой системы, которое может делать то, что делает ваш показанный код, но стандартным и простым способом C++ (например, с использованием итераторов и т. д.).

Some programmer dude 07.02.2023 23:19

Кстати, delete handle;? Только delete то, что явно получено new. Не делай delete того, чего не делал new.

Some programmer dude 07.02.2023 23:20

Тоже const bool removeDir = NULL? Прежде всего, NULL — это макрос обратной совместимости C для нулевых указателей. Если вы хотите установить переменную bool, используйте стандартные значения true и false.

Some programmer dude 07.02.2023 23:22

@Someprogrammerdude Спасибо!! Вы можете написать пример умного указателя в этом случае?

Ohad Porat 07.02.2023 23:27

Дубликат Реализация RAII на итерации папки

Axalo 07.02.2023 23:32

Можете ли вы исправить мой код своими комментариями? @ХансПассант

Ohad Porat 07.02.2023 23:32

@OhadPorat Поиск в Интернете FindFirstFileW RAII мог бы сэкономить вам время.

Axalo 07.02.2023 23:34

unique_ptr<> не имеет деструктора, вызывающего CloseHandle(). Вы должны сделать свой собственный класс. Если ссылка вам не поможет, возможно, оставьте это на полке на некоторое время.

Hans Passant 07.02.2023 23:45

Для этого WIL предоставляет unique_hfind.

IInspectable 08.02.2023 08:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
11
97
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Лучшее решение — сделать средство удаления, которое может вызывать FindClose:

struct FindCloser {
  typedef HANDLE pointer;
  void operator()(HANDLE h) const {FindClose(h);}
};

И затем мы делаем typedef:

using FindHandle = std::unique_ptr<HANDLE, FindCloser>;

И тогда RAII в вашем коде тривиален:

FindHandle handle = FindFirstFileW(path_for_search.c_str(), ffd.get());

Вы, вероятно, также захотите что-то подобное для CloseHandle:

struct HandleCloser {
    typedef HANDLE pointer;
    void operator()(HANDLE h) const {CloseHandle(h);}
};
using RaiiHandle = std::unique_ptr<HANDLE, HandleCloser>;

Теоретически можно использовать std::unique_ptr<void,BOOL(WINAPI *)(HANDLE)>, а затем передать CloseHandle в качестве второго параметра конструктору, но это (A) неприятно, (B) больше и (C) медленнее. Структура FindCloser не имеет состояния (занимает 0 байт в памяти) и легко встраивается. BOOL(WINAPI *)(HANDLE) занимает дополнительные ~8 байт в каждом unique_ptr, и компилятору сложнее доказать, что BOOL(WINAPI *)(HANDLE) всегда будет указывать на FindClose, поэтому его часто нельзя встроить.

Не может ли пользовательское средство удаления быть лямбдой? Я думаю, так будет аккуратнее.

Paul Sanders 08.02.2023 00:47

@PaulSanders: Можно, но у вас должен быть std::unique_ptr<HANDLE, decltype(FindCloserLambda)>, что немного странно, но работает. Однако лямбда должна быть объявлена ​​и определена до создания указателя, поэтому в этом нет особого смысла.

Mooing Duck 08.02.2023 00:59

Почему std::unique_ptr<void,BOOL(WINAPI *)(HANDLE)> будет медленнее, чем (предположительно) пользовательское средство удаления, которое делает то же самое?

IInspectable 08.02.2023 11:53

@IInspectable Я уточнил. Структура FindCloser не имеет состояния (занимает 0 байт в памяти) и легко встраивается. BOOL(WINAPI *)(HANDLE) занимает дополнительные ~8 байт в каждом unique_ptr, и компилятору сложнее доказать, что BOOL(WINAPI *)(HANDLE) всегда будет указывать на FindClose, поэтому его часто нельзя встроить.

Mooing Duck 08.02.2023 17:41

Другие вопросы по теме