次の方法で共有


コンパイラ エラー C2956

通常の割り当て解除関数である 'function' が配置の割り当て解除関数として選択されることになります

配置の新しい式で見つかった割り当て解除関数は、通常の割り当て解除関数のいずれかと一致します。 暗黙的なコンパイラによって生成された割り当て解除または明示的な delete (または delete[]) は、間違った割り当て解除関数を使用します。

解説

エラー C2956 は、メモリ リークやランタイム クラッシュの原因となる可能性のある方法で 配置の新しい式 (パラメーターを受け取る new 式) を使用したことを示します。 通常は、結果の値を一般的な方法で削除できないことを意味します。 つまり、コード内の明示的な delete (または delete[]) 式、またはコンストラクターが例外をスローしたときの暗黙的な割り当て解除のいずれかが、間違った operator delete を呼び出すか、間違ったパラメーターを指定する可能性があります。

C++ 標準ではstd::size_t (C++14 以降)、std::align_val_t (C++17 以降)、およびstd::destroying_delete_t (C++20 以降) の追加パラメーターを受け取るoperator deleteまたはoperator delete[]のオーバーロードとして、割り当て解除関数を指定します。 配置の新しい式を使用すると、コンパイラは同じパラメーター (最初の式の後) を受け取る一致する operator delete 関数を検索します。 1 つが見つかり、そのシグネチャが通常の割り当て解除関数と一致する場合、コンパイラはエラー C2956 を報告します。

問題を解決する方法は、意図の一部によって異なります。 たとえば、C++11 では、アロケーターに値を渡すためにクラス内の追加のsize_t パラメーターを受け取るoperator newオーバーロードを定義できます。 C++14 では、同じコードで次のエラーが発生するようになりました。

#include <new>
struct T {
    void* operator new(std::size_t, std::size_t); // Placement allocation function
    void operator delete(void*, std::size_t); // now considered a usual deallocation function
};

T* p = new (0) T;   // error: usual deallocation function would be chosen as placement deallocation function

オブジェクトのオーバーアラインメモリを指定する場合は、代わりに alignasを使用して型に直接配置を指定できます。 alignasの詳細については、「Alignment」を参照してください。

ヒープ割り当てネイティブ型または配列に対してオーバーアラインメモリを指定する場合は、alignas指定子を持つstructまたはclassでラップします。 その後、通常の new 式と delete 式は、意図した配置を持つインスタンスを割り当ておよび割り当て解除できます。

この例では、 new-expression は、 std::align_val_t型の引数を持つ配置構文を使用します。 ただし、型Tでは配置要件が指定されていないため、T*delete-expressionでは、一致するオーバーアライン割り当て解除関数は呼び出されません。 代わりに、コンパイラは通常の割り当て解除関数 void operator delete(void* ptr) noexceptを呼び出します。これは、オーバーアラインされた割り当てを処理しません。 コンパイラは、クラッシュやメモリ リークを引き起こすのではなく、この配置 newの使用に関するエラーを報告します。

#include <new>
struct T {};

int main()
{
    T* p = new (std::align_val_t{64}) T; // C2956
    delete p; // ordinary, not over-aligned delete
}

この問題を解決するには、Talignas指定子を適用します。

#include <new>
struct alignas(64) T {};

int main()
{
    T* p = new T; // invokes ::operator new(std::size_t, std::align_val_t)
    delete p; // now invokes ::operator delete(void*, std::align_val_t)
}