Поделиться через


Ошибка компилятора C2956

обычная функция сделки "function" будет выбрана в качестве функции размещения сделки

Замечания

Функция распределения сделки, найденная для нового выражения размещения, соответствует одной из обычных функций распределения сделки. Либо неявное размещение сделки, созданное компилятором, либо явное (илиdelete) будет использовать неправильную delete[] функцию распределения сделки.

Ошибка C2956 указывает, что вы использовали новое выражение размещения ( new выражение, которое принимает параметры) таким образом, что может привести к утечке памяти или сбою среды выполнения. Обычно это означает, что результирующее значение не может быть удалено обычным образом. То есть явное delete (или delete[]) выражение в коде или неявное размещение сделки при возникновении исключения может вызвать неправильное operator delete или указать его неправильными параметрами.

Стандарт C++ задает обычные функции распределения сделки как перегрузки operator delete или operator delete[] которые принимают дополнительные параметры типа std::size_t (C++14 или более поздней версии), (C++17 или более поздней версии) std::align_val_t и 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разделе "Выравнивание".

Если вы намерены указать слишком выровненную память для выделенного кучей собственного типа или массива, заключите его в описатель struct или class с этим alignas описателями. Затем обычные new и delete выражения могут выделять и освобождать экземпляры, которые имеют предполагаемое выравнивание.

Пример

В этом примере new-expression используется синтаксис размещения с аргументом типа std::align_val_t. Однако, так как тип T не указывает требование выравнивания, в ней delete-expressionT* не будет вызываться соответствующая функция распределения сделки с выравниванием. Вместо этого компилятор вызовет обычную функцию 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)
}