コンパイラ エラー 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
}
この問題を解決するには、T
にalignas
指定子を適用します。
#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)
}