Как можно допустить утечку памяти при использовании unique_ptr в C++?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Утечка памяти при использовании std::unique_ptr возможна в следующих случаях:
-
Некорректное использование собственной реализации удалителя (Deleter): Если пользовательский удалитель не освобождает выделенный ресурс должным образом (например, вызывает
deleteвместоdelete[]для массива или не вызывает соответствующую функцию освобождения ресурса).#include <memory> #include <iostream> struct MyDeleter { void operator()(int* ptr) const { // ОШИБКА: Должен быть delete[], а не delete delete ptr; std::cout << "Called incorrect deleter" << std::endl; } }; int main() { // Выделяем массив, но используем некорректный удалитель std::unique_ptr<int, MyDeleter> ptr(new int[10], MyDeleter()); // Память, выделенная как массив, не будет освобождена полностью при выходе из области видимости ptr return 0; } -
Передача сырого указателя из
unique_ptrв функцию, которая затем принимает владение им и не освобождает: Передача владения должна выполняться явно с помощьюstd::move. Если вы передаетеget()или сырой указатель, а затем не заботитесь об освобождении в другом месте, это может привести к утечке.#include <memory> #include <iostream> void process_and_lose(int* raw_ptr) { // Функция "забывает" delete raw_ptr std::cout << "Processing " << *raw_ptr << std::endl; // Утечка памяти! } int main() { std::unique_ptr<int> ptr(new int(42)); // Получаем сырой указатель int* raw = ptr.get(); process_and_lose(raw); // ptr все еще управляет памятью, но raw_ptr стал сиротой // В данном случае утечки нет, потому что ptr освободит память // Но если бы ptr был сброшен или переназначен до вызова process_and_lose, // и process_and_lose не удалил его, утечка была бы return 0; }Исправленный пример с потенциальной утечкой (если передаем владение, но функция не удаляет):
#include <memory> #include <iostream> void function_that_takes_ownership_and_leaks(int* owned_ptr) { // Предполагается, что owned_ptr теперь принадлежит этой функции std::cout << "Taking ownership and leaking: " << *owned_ptr << std::endl; // Утечка: owned_ptr не удаляется } int main() { std::unique_ptr<int> ptr(new int(100)); // Передаем владение сырому указателю function_that_takes_ownership_and_leaks(ptr.release()); // ptr теперь пуст, его ресурс (указатель) не будет освобожден автоматически return 0; } -
Исключения между выделением памяти и оборачиванием в
unique_ptr: Несмотря на то, чтоstd::make_uniqueпредотвращает это, прямое использованиеnewс последующим конструкторомunique_ptrможет привести к утечке, если между ними возникнет исключение.#include <memory> #include <vector> class Resource { public: Resource() { std::cout << "Resource created" << std::endl;} ~Resource() { std::cout << "Resource destroyed" << std::endl;} }; void might_throw() { throw std::runtime_error("Oops!"); } int main() { Resource* res = new Resource(); // Выделение памяти try { might_throw(); // Исключение возникает здесь std::unique_ptr<Resource> ptr(res); // Эта строка не будет достигнута } catch (const std::runtime_error& e) { std::cerr << "Caught exception: " << e.what() << std::endl; // res* не был обернут в unique_ptr и не был удален // Это приводит к утечке! } // Корректный способ: std::make_unique<Resource>() или std::unique_ptr<Resource> ptr(new Resource()); return 0; }
В целом, утечка памяти при корректном использовании std::unique_ptr крайне маловероятна, поскольку его основная цель — автоматическое управление ресурсами, предотвращая утечки в типичных сценариях. Проблемы возникают при выходе за рамки его стандартного использования (собственные удалители, release(), взаимодействие с сырыми указателями).