コンパイラの警告 (レベル 1) C4291

'declaration': 一致する演算子 delete が見つかりません。初期化により例外がスローされると、メモリが解放されません

placement new が使用されていますが、対応する placement delete がありません。

オブジェクトのメモリを operator new で割り当てると、そのオブジェクトのコンストラクターが呼び出されます。 コンストラクターから例外がスローされた場合、そのオブジェクト用に割り当てられていたメモリの割り当てを解除する必要があります。 これは、operator new に対応する operator delete 関数が存在しない限り実行できません。

別途引数を付けずに operator new を使用し、例外処理を有効にする /GX/EHs、/EHa のいずれかのオプションを指定してコンパイルした場合、コンストラクターが例外をスローしたときに operator delete を呼び出すコードがコンパイラによって生成されます。

placement 形式の new 演算子 (割り当てのサイズに加えて引数が付く形式) を使用していて、オブジェクトのコンストラクターから例外がスローされた場合でも、コンパイラは、operator delete を呼び出すコードを生成します。ただし、それが行われるのは、メモリの割り当てを行った placement 形式の operator new に対応する placement 形式の operator delete が存在する場合に限られます。 次に例を示します。

// C4291.cpp
// compile with: /EHsc /W1
#include <malloc.h>

class CList
{
public:
   CList(int)
   {
      throw "Fail!";
   }
};

void* operator new(size_t size, char* pszFilename, int nLine)
{
   return malloc(size);
}

int main(void)
{
   try
   {
      // This will call ::operator new(unsigned int) to allocate heap
      // memory. Heap memory pointed to by pList1 will automatically be
      // deallocated by a call to ::operator delete(void*) when
      // CList::CList(int) throws an exception.
      CList* pList1 = new CList(10);
   }
   catch (...)
   {
   }

   try
   {
      // This will call the overloaded ::operator new(size_t, char*, int)
      // to allocate heap memory. When CList::CList(int) throws an
      // exception, ::operator delete(void*, char*, int) should be called
      // to deallocate the memory pointed to by pList2. Since
      // ::operator delete(void*, char*, int) has not been implemented,
      // memory will be leaked when the deallocation cannot occur.
      CList* pList2 = new(__FILE__, __LINE__) CList(20);   // C4291
   }
   catch (...)
   {
   }
}

上の例では、placement 形式の operator new に対応する placement 形式の operator delete が定義されていないため、警告 C4291 が生成されます。 この問題を解決するには、main の上に次のコードを挿入します。 オーバーロードされた operator delete 関数のすべてのパラメーターが、第 1 パラメーターを除き、オーバーロードされた operator new のそれと一致している点に注目してください。

void operator delete(void* pMem, char* pszFilename, int nLine)
{
   free(pMem);
}