Не о милицанере

А об освобождении ресурсов.
Внесите ясность в мою голову, пожалуйста.
Система предоставляет разнообразные ресурсы (например, память на куче).
Приложение их берет, пользуется и возвращает.
Низкий уровень:
...
handle_t h = allocate(...);
...
use(h)...
...
release(h);
...
Причем освобождать нужно во
всех случаях, когда ресурс более не нужен. В том числе во всех ветках программы, в обработке исключений и т.д.
Для ресурса типа "память" есть различные методы сборки мусора:
— моментальный (умные указатели различных видов)
— отложенный (специальная организация кучи + умные указатели поддерживаемые компилятором)
А как быть с другими ресурсами, например, с файлами?
На C++ это решается с помощью умного хэндлера, который в деструкторе делает что-то полезное.
В сочетании с моментальной уборкой мусора это прекрасно работает.
Так почему же Java, C#, MC отказались от этого, оставляя программисту
исключительно вручную управлять
каждым экземпляром ресурса?
В лучшем случае автоматизировать можно обработку исключений
File* pFile = 0;
Mutex* pMutex = 0;
__try
{
pFile = new File("hello.txt", "rw+");
pMutex = new Mutex();
...
}
__finally
{
if(pFile) pFile->close();
if(pMutex) pMutex->destroy();
}
// судьбой указателей и объектов-оберток займется мусоросборщик
Такие фокусы возможны только в ограниченном контексте (например, в теле функции).
Если какой-то объект содержит не только подчиненные объекты (этим занимается мусоросборщик), но еще и какие-то ресурсы в этих объектах или в самом себе, то этот объект должен иметь функцию финализации
class CompoundResource
{
File* m_pFile;
Mutex* m_pMutex;
HANDLE m_hDllModule;
public:
void finalize()
{
if(m_pFile) { m_pFile->close(); m_pFile = NULL; }
if(m_pMutex) { m_pMutex->destroy(); m_pMutex = NULL; }
if(m_hDllModule) { FreeLibrary(m_hDllModule); m_hDllModule = NULL; }
}
...
};
Получается, мы сочинили псевдо-деструктор, который будем вызывать вручную!
А если не вызывать — то эти ресурсы прокукуют как минимум до сборки мусора, где сборщик вызовет настоящий деструктор (в котором вызывается эта функция финализации) — а если алгоритм икнет — то вообще до конца процесса. А, по последним сведениям, .net-овский алгоритм икает.
Ну и что мы тогда выигрываем?
+ Избавились от глупых/умных указателей, от потерь памяти, от проблемы кольцевых ссылок (главный враг моментального сборщика мусора, как например, COM)
— Пришли к необходимости ручной финализации. Дожили!
И не надо говорить, что это надуманная проблема, что рано или поздно процесс завершится и отдаст все концы.
Серверное приложение может отлично выжрать весь лимит открытых файлов, после чего ОС пошлет всех на.
Где же выход?