3

私はいくつかの COM および ATL コードを書いていますが、何らかの理由ですべてのコードがorCoTaskMemAllocの代わりにメモリを割り当てるために使用しています。だから私はこのコーディングスタイルに従い、.newmallocCoTaskMemAlloc

私の先生は、いつでもdelete、またはfreeいつメモリを割り当てるかを教えてくれました。ただし、 ?CoTaskMemFreeを使用する場合、常に呼び出す必要があるかどうかはわかりません。CoTaskMemAlloc

4

3 に答える 3

10

CRT が提供する new/malloc および delete/free の使用は、COM 相互運用の問題です。それらを機能させるには、CRT の同じコピーがメモリの割り当てと解放の両方を行うことが非常に重要です。COM 相互運用シナリオでこれを強制することは不可能です。COM サーバーとクライアントは、異なるバージョンの CRT を使用することが実質的に保証されます。それぞれ独自のヒープを使用して割り当てます。これにより、Windows XP で診断不能なメモリ リークが発生します。Vista 以降ではハード例外です。

これが、サーバーとクライアントの両方で使用されるプロセス内の単一の定義済みヒープである COM ヒープが存在する理由です。IMalloc は、その共有ヒープにアクセスするための汎用インターフェイスです。CoTaskMemAlloc() および CoTaskMemFree() は、そのインターフェイスを使用するためのシステム提供のヘルパー関数です。

とはいえ、これはサーバーがメモリを割り当て、クライアントがそれを解放する必要がある場合にのみ必要です。またはその逆です。これは、相互運用シナリオでは常にまれなことですが、事故の可能性が高すぎます。COM オートメーションでは、既にラップされている BSTR と SAFEARRAY の 2 つのケースしかありません。メソッドの呼び出し元がメモリを提供し、呼び出し先がそれを埋めることにより、他のケースではそれを回避します。これにより、強力な最適化も可能になり、メモリは呼び出し元のスタックから取得される可能性があります。

コードを確認し、誰がメモリを割り当て、誰が解放する必要があるかを確認します。両方が同じモジュールに存在する場合、new/malloc を使用しても問題ありません。これは、同じ CRT インスタンスがそれを処理することが確実に保証されるためです。そうでない場合は、呼び出し元がメモリを提供して解放するように修正することを検討してください。

于 2012-04-07T15:56:30.697 に答える
4

メモリの割り当てと解放は、常に同じソースから行う必要があります。使用する場合は、使用してメモリを解放する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;
于 2012-04-07T15:22:35.230 に答える
2

質問に対する答えは次のとおりです。はい、CoTaskMemFree を使用して、CoTaskMemAlloc で割り当てられたメモリを解放する必要があります。

他の回答は、COM サーバーと COM クライアントの間で渡されるメモリに CoTaskMemAlloc と CoTaskMemFree が必要な理由を説明していますが、質問には直接答えていません。

あなたの先生は正しかった: どのリソースにも、対応するリリース関数を常に使用する必要があります。new を使用する場合は、delete を使用してください。malloc を使用する場合は、free を使用してください。CreateFile を使用する場合は、CloseHandle を使用します。等。

さらに良いことに、C++ では、コンストラクタでリソースを割り当て、デストラクタでリソースを解放する RAII オブジェクトを使用し、そのままの関数の代わりにこれらの RAII ラッパーを使用します。これにより、例外のようなものが発生した場合でも、リークしないコードを簡単かつクリーンに記述できます。

標準テンプレート ライブラリは、RAII を実装するコンテナーを提供します。そのため、裸のメモリを割り当てて自分で管理しようとするのではなく、std::vector または std::string の使用方法を学ぶ必要があります。std::shared_ptr や std::unique_ptr などのスマート ポインターもあり、適切なリリース呼び出しが常に適切なタイミングで行われるようにするために使用できます。

ATL は、COM オブジェクトの参照カウントを処理するラッパー オブジェクトである ATL::CComPtr のようないくつかのクラスを提供します。これらは、正しく使用するのに絶対確実というわけではありません。実際、最新の STL クラスのほとんどよりも落とし穴がいくつかあるため、ドキュメントを注意深く読んでください。正しく使用すると、AddRef 呼び出しと Release 呼び出しがすべて一致することを確認するのは比較的簡単です。

于 2013-03-14T17:24:21.420 に答える