编译器错误 C2956

常用解除分配函数 'function'会被选为放置解除分配函数。

为放置新表达式找到的解除分配函数与一个常用解除分配函数匹配。 隐式编译器生成的解除分配或显式 delete(或 delete[])将使用错误的解除分配函数。

备注

错误 C2956 指示使用放置置新表达式(采用参数的表达式 new)的方式可能会导致内存泄漏或运行时崩溃。 它通常意味着无法以典型方式删除生成的值。 也就是说,代码中的显式 delete(或 delete[])表达式,或者在构造函数引发异常时隐式解除分配,可以调用错误 operator delete 或提供错误的参数。

C++ 标准将常用的解除分配函数指定为 operator delete 的重载,或者采用类型 std::size_t 的其他参数的 operator delete[](C++14 或更高版本)、std::align_val_t(C++17 或更高版本),以及 std::destroying_delete_t(C++20 或更高版本)。 使用放置新表达式时,编译器会查找(在第一个后)采用相同参数的匹配 operator delete 函数。 如果找到一个并且其签名与常用的解除分配函数匹配,编译器将报告错误 C2956。

解决问题的方式取决于你的意图。 例如,在 C++ 11 中,可以定义 operator new 重载,该重载采用类中的额外 size_t 参数将值传递给分配器。 在 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 的详细信息,请参阅对齐

如果打算为堆分配的本机类型或数组指定过度对齐的内存,请将其包装在具有 alignas 说明符的 structclass 中。 然后,普通 newdelete 表达式可以分配并解除分配具有预期对齐方式的实例。

示例

在此示例中,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
}

若要解决此问题,请将 alignas 说明符应用于 T

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