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


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

Объявление: попытка ссылаться на удаленную функцию

Компилятор обнаружил попытку ссылаться на deleted функцию. Эта ошибка может быть вызвана вызовом функции-члена, которая была явно помечена как = deleted в исходном коде. Эта ошибка также может быть вызвана вызовом неявной специальной функции-члена структуры или класса, которая автоматически объявлена и помечена deleted компилятором. Дополнительные сведения о том, когда компилятор автоматически создает default или deleted специальные функции-члены, см. в разделе "Специальные функции-члены".

Пример: явно удаленные функции

Вызов явной deleted функции вызывает эту ошибку. Явная deleted функция-член подразумевает, что класс или структуру намеренно предназначен для предотвращения его использования, поэтому для устранения этой проблемы следует изменить код, чтобы избежать его.

// C2280_explicit.cpp
// compile with: cl /c /W4 C2280_explicit.cpp
struct A {
    A();
    A(int) = delete;
};

struct B {
    A a1;
    A a2 = A(3); // C2280, calls deleted A::A(int)
    // To fix, remove the call to A(int)
};

void f() {
    B b;    // calls implicit B::B(void)
}

Пример: неинициализированные элементы данных

Неинициализированный элемент данных ссылочного типа или const член данных приводит к неявному объявлению конструктора по умолчанию компилятором deleted . Чтобы устранить эту проблему, инициализировать элемент данных при объявлении.

// C2280_uninit.cpp
// compile with: cl /c C2280_uninit.cpp
struct A {
    const int i; // uninitialized const-qualified data
    // members or reference type data members cause
    // the implicit default constructor to be deleted.
    // To fix, initialize the value in the declaration:
    // const int i = 42;
} a;    // C2280

Пример: элементы ссылочных и константных данных

Элемент const данных типа или ссылочного типа приводит компилятора к объявлению deleted оператора назначения копирования. После инициализации эти члены не могут быть назначены, поэтому простое копирование или перемещение не может работать. Чтобы устранить эту проблему, рекомендуется изменить логику, чтобы удалить операции назначения, которые вызывают ошибку.

// C2280_ref.cpp
// compile with: cl /c C2280_ref.cpp
extern int k;
struct A {
    A();
    int& ri = k; // a const or reference data member causes
    // implicit copy assignment operator to be deleted.
};

void f() {
    A a1, a2;
    // To fix, consider removing this assignment.
    a2 = a1;    // C2280
}

Пример: Movable удаляет неявную копию

Если класс объявляет конструктор перемещения или оператор назначения перемещения, но не объявляет явно конструктор копирования, компилятор неявно объявляет конструктор копирования и определяет его как deleted. Аналогичным образом, если класс объявляет конструктор перемещения или оператор назначения перемещения, но не объявляет явным образом оператор назначения копирования, компилятор неявно объявляет оператор назначения копирования и определяет его как deleted. Чтобы устранить эту проблему, необходимо явно объявить эти члены.

При появлении ошибки C2280 в связи с ней unique_ptrпочти наверняка возникает ошибка, так как вы пытаетесь вызвать конструктор копирования, который является deleted функцией. По дизайну unique_ptr невозможно скопировать. Вместо этого используйте конструктор перемещения для передачи владения.

// C2280_move.cpp
// compile with: cl /c C2280_move.cpp
class base
{
public:
    base();
    ~base();
    base(base&&);
    // Move constructor causes copy constructor to be
    // implicitly declared as deleted. To fix this
    // issue, you can explicitly declare a copy constructor:
    // base(base&);
    // If you want the compiler default version, do this:
    // base(base&) = default;
};

void copy(base *p)
{
    base b{*p};  // C2280
}

Пример: варианты и переменные члены

Версии компилятора до Visual Studio 2015 с обновлением 2 не соответствуют требованиям и создают конструкторы по умолчанию и деструкторы для анонимных союзов. Теперь они неявно объявлены как deleted. Эти версии также позволили несоответствующее неявное определение конструкторов копирования default и перемещения, default а также операторы назначения копирования и перемещения в классах и конструкциях, имеющих volatile переменные-члены. Теперь компилятор считает, что они имеют нетривиальные конструкторы и операторы назначения, и не создает default реализации. Если такой класс является членом объединения или анонимного объединения внутри класса, конструкторы копирования и перемещения, а также операторы назначения копирования и перемещения профсоюза или класса неявно определяются как deleted. Чтобы устранить эту проблему, необходимо явно объявить необходимые специальные функции-члены.

// C2280_variant.cpp
// compile with: cl /c C2280_variant.cpp
struct A {
    A() = default;
    A(const A&);
};

struct B {
    union {
        A a;
        int i;
    };
    // To fix this issue, declare the required
    // special member functions:
    // B();
    // B(const B& b);
};

int main() {
    B b1;
    B b2(b1);  // C2280
}

Пример: удаленные косвенные базовые элементы

Версии компилятора до Visual Studio 2015 с обновлением 2 не соответствуют требованиям и позволяют производному классу вызывать специальные функции-члены косвенно производных private virtual базовых классов. Компилятор теперь выдает ошибку компилятора C2280 при выполнении такого вызова.

В этом примере класс top косвенно является производным от частной виртуальной.base В соответствии с кодом это делает элементы base недоступными top; объект типа top не может быть создан или уничтожен по умолчанию. Чтобы устранить эту проблему в коде, зависящей от старого поведения компилятора, измените промежуточный класс на использование protected virtual производной или измените top класс, чтобы использовать прямую производную функцию:

// C2280_indirect.cpp
// compile with: cl /c C2280_indirect.cpp
class base
{
protected:
    base();
    ~base();
};

class middle : private virtual base {};
// Possible fix: Replace line above with:
// class middle : protected virtual base {};
class top : public virtual middle {};    // C4594, C4624
// Another possible fix: use direct derivation:
// class top : public virtual middle, private virtual base {};

void destroy(top *p)
{
    delete p;  // C2280
}