分享方式:


編譯器錯誤 C2280

' declaration ': 嘗試參考已刪除的函式

編譯器偵測到嘗試參考函 deleted 式。 此錯誤可能是由呼叫已明確標示為 = deleted 原始程式碼中的成員函式所造成。 這個錯誤也可能是因為對結構或類別之隱含特殊成員函式的呼叫所造成,該函式會自動宣告並標示 deleted 為編譯器。 如需編譯器自動產生 defaultdeleted 特殊成員函式時的詳細資訊,請參閱 特殊成員函式

範例:明確刪除的函式

明確函式的 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 資料成員

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
}

範例:可移動刪除隱含複製

如果類別宣告移動建構函式或移動指派運算子,但不明確宣告複製建構函式,編譯器會隱含宣告複製建構函式,並將其定義為 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
}

範例:Variant 和 volatile 成員

Visual Studio 2015 Update 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 Update 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
}