Приведите примеры из стандартной библиотеки C++, которые используют RAII
Что проверяют
Знаете ли вы, что RAII это про любой ресурс, а не только про память, и понимаете ли механизм: захват в конструкторе, освобождение в деструкторе, точка освобождения это выход из области видимости, в том числе при исключении.
Как отвечать
Перечисляйте парами, класс и ресурс, которым он владеет:
std::unique_ptrиstd::shared_ptr: динамическая память, а с пользовательским удалителем и любой чужой ресурс вродеFILE*или дескриптора;std::vector,std::stringи остальные контейнеры: буфер, выделенный через аллокатор;std::lock_guard,std::unique_lock,std::scoped_lock: захваченный мьютекс, причём последний берёт сразу несколько без риска взаимной блокировки;std::fstream: открытый файл, деструктор закрывает его сам;std::jthread: присоединение потока в деструкторе вместе с запросом на остановку.
Дальше объясните, почему это работает: при выбросе исключения раскрутка стека вызывает деструкторы уже созданных объектов, поэтому мьютекс отпускается, а файл закрывается на любом пути выхода.
{
std::lock_guard<std::mutex> guard(m);
mayThrow();
}Ручная пара «открыл и закрыл» такой гарантии не даёт: её ломает ранний return.
Где спотыкаются
Сводят всё к умным указателям. Тогда вопрос про файлы, мьютексы и сокеты застаёт врасплох, хотя на них выгода заметнее: утечка блокировки обходится дороже утечки памяти.
Создают безымянный охранник: std::lock_guard<std::mutex>(m);. Это временный объект, он умирает в той же строке, и критическая секция остаётся незащищённой. Компилятор молчит, а гонка ловится месяцами.
Называют std::thread примером RAII. Его деструктор не присоединяет поток, а вызывает std::terminate, если не было join или detach. Ровно поэтому и появился std::jthread, доводящий дело до конца.