When using CoTaskMemAlloc, should I always call CoTaskMemFree?

I am writing COM and ATL code and for some reason all the code uses CoTaskMemAlloc

memory allocation instead of new

or malloc

. So I followed this coding style and I also use CoTaskMemAlloc

.

My teachers taught me always delete

or free

with memory allocation. However, I'm not sure if I should always call CoTaskMemFree

if I use CoTaskMemAlloc

?

+3


source to share


3 answers


Using a CRT assuming new / malloc and delete / free are a COM interop issue. To make them work, it is very important that the same copy of the CRT allocates and frees memory. This is not possible in a COM interop scenario, your COM server and client are almost guaranteed to use different versions of the CRT. Each of them uses its own heap for allocation. This causes unplayable memory leaks in Windows XP, hard exception in Vista and above.

This is why there is a COM heap, one predefined heap in a process that is used by both the server and the client. IMalloc is a generic interface for accessing this shared heap, CoTaskMemAlloc () and CoTaskMemFree () are system-provided helper functions for using this interface.



However, this is only necessary when the server is allocating memory and the client needs to free it. Or vice versa. Which should always be rare in an interaction scenario, the chances of accidents are far too great. There are only two such cases in COM Automation, BSTR and SAFEARRAY, which are already wrapped. You avoid this in other cases where the caller provides memory and the caller fills it. It also allows for a lot of optimization, memory can come from the caller's stack.

Review the code and check who is allocating memory and who should be releasing it. If they exist in the same module, then using new / malloc is fine, because now there is a strong guarantee that the same CRT instance will take care of it. If it is not, then consider latching it so that the caller provides the memory and frees it.

+8


source


Memory allocation and deallocation must always come from the same source. If you are using CoTaskMemAlloc

, you must use CoTaskMemFree

to allocate memory.

Note in C ++, although the memory management action and object construction / destroy ( new / delete

) are independent actions. You can configure individual objects to use a different memory allocator and still use the standard syntax new / delete

, which is preferred. for example

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);
  }   
};

      



Now I can use this type just like any other C ++ type and still the memory will come from the COM heap

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

      

+2


source


The answer to the question is yes, you should use CoTaskMemFree to free memory allocated with CoTaskMemAlloc.

The other answers explain well why CoTaskMemAlloc and CoTaskMemFree are required for memory transferred between COM servers and COM clients, but they did not directly answer your question.

Your teacher was right: you should always use the appropriate release function for any resource. If you are using new then use delete. If you are using malloc use the free one. If you are using CreateFile use CloseHandle. Etc.

Better yet, in C ++, use RAII objects that allocate a resource in the constructor and free the resource in the destructor, and then use those RAII wrappers instead of a bare function. This simplifies and cleans up code that doesn't flow even if you get something like an exception.

The Standard Template Library provides containers that implement RAII, so you should learn to use std :: vector or std :: string rather than allocating bare memory and trying to manage it yourself. There are also smart pointers like std :: shared_ptr and std :: unique_ptr that can be used to ensure the right conversation choices at the right time.

ATL provides some classes like ATL :: CComPtr, which are wrapper objects that handle COM object reference counting for you. They are not reliable to work properly and, in fact, have a few more fixes than most modern STL classes, so read the documentation carefully. When used correctly, it is relatively easy to make sure that the AddRef and Release calls are all the same.

0


source







All Articles