2012-04-07 15 views
3

Я пишу код COM и ATL, и по какой-то причине весь код использует CoTaskMemAlloc для выделения памяти вместо new или malloc. Поэтому я следил за этим стилем кодирования, и я также использую CoTaskMemAlloc.При использовании CoTaskMemAlloc, должен ли я всегда вызывать CoTaskMemFree?

Мои учителя учили меня всегда delete или free при распределении памяти. Однако я не уверен, должен ли я всегда звонить CoTaskMemFree, если я использую CoTaskMemAlloc?

+0

Связанные чтения: [Распределение и освобождение памяти через границы модулей] (http://blogs.msdn.com/b/oldnewthing/archive/2006/09/15/755966.aspx). – GSerg

ответ

2

Выделение и освобождение памяти всегда должно происходить из одного источника. Если вы используете CoTaskMemAlloc, тогда вы должны использовать CoTaskMemFree для выделения памяти.

Замечание в C++, хотя действие управления памятью и строительство объекта/уничтожения (new/delete) являются независимыми действиями. Можно настроить конкретные объекты для использования другого распределителя памяти и по-прежнему использовать стандартный синтаксис new/delete, который является предпочтительным. Например

class MyClass { 
public: 
    void* operator new(size_t size) { 
    return ::CoTaskMemAlloc(size); 
    } 
    void* operator new[](size_t size) { 
    return ::CoTaskMemAlloc(size); 
    } 
    void operator delete(void* pMemory) { 
    ::CoTaskMemFree(pMemory); 
    } 
    void operator delete[](void* pMemory) { 
    ::CoTaskMemFree(pMemory); 
    } 
}; 

Теперь я могу использовать этот тип, как и любой тип другой C++ и все же память будет поступать из COM кучи

// Normal object construction but memory comes from CoTaskMemAlloc 
MyClass *pClass = new MyClass(); 
... 
// Normal object destruction and memory freed from CoTaskMemFree 
delete pClass; 
8

Использование ЭЛТ поданному новый/таНос и удалять/свободный от проблема в COM-взаимодействии. Чтобы заставить их работать, очень важно, чтобы одна и та же копия CRT выделяла и освобождала память. Это невозможно реализовать в сценарии взаимодействия COM, ваш COM-сервер и клиент практически гарантированно используют разные версии CRT. Каждый из них использует свою кучу для выделения. Это вызывает неигромые утечки памяти в Windows XP, жесткое исключение в Vista и выше.

Именно поэтому существует куча COM, одна предопределенная куча в процессе, который используется как сервером, так и клиентом. IMalloc - это общий интерфейс для доступа к этой общей куче, CoTaskMemAlloc() и CoTaskMemFree() - это предоставленные системой вспомогательные функции для использования этого интерфейса.

Сообщается, что это только необходимо в случае, когда сервер выделяет память, и клиент должен ее освободить. Или наоборот. Который всегда должен быть редок в сценарии взаимодействия, шансы на несчастные случаи слишком велики. В COM Automation существует только два таких случая: BSTR и SAFEARRAY, которые уже завернуты. Вы избегаете этого в других случаях, когда вызывающий метод предоставляет память, а вызывающая его заполняет. Это также позволяет обеспечить сильную оптимизацию, память может поступать из стека вызывающего абонента.

Просмотрите код и проверьте, кто выделяет память и кто должен ее освободить. Если они существуют в одном модуле, то использование new/malloc прекрасное, потому что теперь есть твердая гарантия, что тот же экземпляр CRT позаботится об этом. Если это не так, подумайте об этом, чтобы вызывающий абонент обеспечивал память и освобождал ее.

0

Ответ на вопрос: Да, вы должны использовать CoTaskMemFree для освобождения памяти, выделенной с помощью CoTaskMemAlloc.

Другие ответы хорошо объясняют, почему CoTaskMemAlloc и CoTaskMemFree необходимы для памяти, передаваемой между COM-серверами и COM-клиентами, но они напрямую не ответили на ваш вопрос.

Ваш учитель был прав: вы должны всегда использовать соответствующую функцию освобождения для любого ресурса. Если вы используете новый, используйте delete. Если вы используете malloc, используйте бесплатный.Если вы используете CreateFile, используйте CloseHandle. И т. Д.

Еще лучше, на C++, используйте объекты RAII, которые выделяют ресурс в конструкторе и освобождают ресурс в деструкторе, а затем используют эти обертки RAII вместо голой функции. Это упрощает и очищает код, который не течет, даже если вы получаете что-то вроде исключения.

Стандартная библиотека шаблонов предоставляет контейнеры, которые реализуют RAII, поэтому вы должны научиться использовать std :: vector или std :: string, а не выделять голой памяти и пытаться управлять ею самостоятельно. Существуют также интеллектуальные указатели, такие как std :: shared_ptr и std :: unique_ptr, которые можно использовать для обеспечения правильного выбора разговора в нужное время.

ATL предоставляет некоторые классы, такие как ATL :: CComPtr, которые являются объектами-оболочками, которые обрабатывают подсчет ссылок на COM-объекты для вас. Они не являются надежными для правильной работы и, по сути, имеют еще несколько исправлений, чем большинство современных классов STL, поэтому внимательно прочитайте документацию. При правильном использовании относительно легко убедиться, что вызовы AddRef и Release все совпадают.

+0

Использование интеллектуальных указателей очень важно в COM (и на C++). Вероятность ошибок при подсчете ссылок очень высока. Использовать CComPtr для созданных объектов; используйте CComHeapPtr, когда возвратная память COM api будет освобождена с помощью CoTaskMemFree (например, StringFromCLSID). – gast128

Смежные вопросы