Ошибка c2280 предпринята попытка ссылки на удаленную функцию

Имеются скромные три строчки плюсового кода, написанные в VS 2015

std::list <sf::TcpSocket> soc;
sf::TcpSocket co;
soc.push_back(co);

На этапе сборки возникает ошибка следующего вида

error C2280: «sf::TcpSocket::TcpSocket(const sf::TcpSocket &)»: предпринята попытка ссылки на удаленную функцию

Ошибку такую вижу впервые, в ранних версиях VS не сталкивался, нашел код ошибки на MSDN, однако ничего внятного там не увидел. Что за зверь такой и как бороться?

задан 29 июн 2016 в 10:04

Jereli's user avatar

3

У класса sf::TcpSocket нет конструктора копирования. Вы уверены что нужно хранить объекты, а не указатели?

std::list<sf::TcpSocket*> soc;
sf::TcpSocket *co = new sf::TcpSocket();
soc.push_back(co);

Если sf::TcpSocket — Ваш класс и Вы уверенны, что в списке нужно хранить именно экземпляры класса, а не указатели на них. то нужно определить конструктор копирования:

sf::TcpSocket::TcpSocket(const sf::TcpSocket &other)
{
    //тут копируем нужные нам объекты
}

ответ дан 29 июн 2016 в 10:20

Александр's user avatar

АлександрАлександр

4,0301 золотой знак10 серебряных знаков19 бронзовых знаков

5

Начиная с c++11 для типов, хранимых в std::vector, не требуется обязательного наличия копирующего конструктора. При этом, правда, потребуется перемещающий.

В случае с Вашим sf::TcpSocket это, конечно, не поможет (судя по описанию), но в определенных ситуациях может быть полезным.

#include <iostream>
#include <vector>

struct S {
    S() { std::cout << "def ctorn"; }
    S(const S&) = delete;
    S(S&&) { std::cout << "mv ctorn"; }
    void f() const { std::cout << "f()n"; }
};

int main() {
    std::vector<S> v;
    v.push_back(S{});
    for(auto& s: v) {
        s.f();
    }
}

Результат выполнения

ответ дан 29 июн 2016 в 16:08

αλεχολυτ's user avatar

αλεχολυταλεχολυτ

28.4k10 золотых знаков57 серебряных знаков118 бронзовых знаков

description title ms.date f1_keywords helpviewer_keywords ms.assetid

Learn more about: Compiler Error C2280

Compiler Error C2280

04/25/2017

C2280

C2280

e6c5b1fb-2b9b-4554-8ff9-775eeb37161b

Compiler Error C2280

declaration‘: attempting to reference a deleted function

The compiler detected an attempt to reference a deleted function. This error can be caused by a call to a member function that has been explicitly marked as = deleted in the source code. This error can also be caused by a call to an implicit special member function of a struct or class that is automatically declared and marked as deleted by the compiler. For more information about when the compiler automatically generates default or deleted special member functions, see Special member functions.

Example: Explicitly deleted functions

A call to an explicitly deleted function causes this error. An explicitly deleted member function implies that the class or struct is intentionally designed to prevent its use, so to fix this issue, you should change your code to avoid it.

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

Example: Uninitialized data members

An uninitialized reference type data member or const data member causes the compiler to implicitly declare a deleted default constructor. To fix this issue, initialize the data member when it is declared.

// 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

Example: Reference and const data members

A const or reference type data member causes the compiler to declare a deleted copy assignment operator. Once initialized, these members can’t be assigned to, so a simple copy or move can’t work. To fix this issue, we recommend you change your logic to remove the assignment operations that cause the error.

// 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
}

Example: Movable deletes implicit copy

If a class declares a move constructor or move assignment operator, but does not explicitly declare a copy constructor, the compiler implicitly declares a copy constructor and defines it as deleted. Similarly, if a class declares a move constructor or move assignment operator, but does not explicitly declare a copy assignment operator, the compiler implicitly declares a copy assignment operator and defines it as deleted. To fix this issue, you must explicitly declare these members.

When you see error C2280 in connection with a unique_ptr, it is almost certainly because you are attempting to invoke its copy constructor, which is a deleted function. By design, a unique_ptr cannot be copied. Use a move constructor to transfer ownership instead.

// 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
}

Example: Variant and volatile members

Versions of the compiler before Visual Studio 2015 Update 2 were non-conforming and generated default constructors and destructors for anonymous unions. These are now implicitly declared as deleted. Those versions also allowed non-conforming implicit definition of default copy and move constructors and default copy and move assignment operators in classes and structs that have volatile member variables. The compiler now considers these to have non-trivial constructors and assignment operators, and doesn’t generate default implementations. When such a class is a member of a union, or an anonymous union inside of a class, the copy and move constructors and copy and move assignment operators of the union or class are implicitly defined as deleted. To fix this issue, you must explicitly declare the required special member functions.

// 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
}

Example: Indirect base members deleted

Versions of the compiler before Visual Studio 2015 Update 2 were non-conforming and allowed a derived class to call special member functions of indirectly-derived private virtual base classes. The compiler now issues compiler error C2280 when such a call is made.

In this example, class top indirectly derives from private virtual base. In conforming code, this makes the members of base inaccessible to top; an object of type top can’t be default constructed or destroyed. To fix this issue in code that relied on the old compiler behavior, change the intermediate class to use protected virtual derivation, or change the top class to use direct derivation:

// 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
}

This snippet is compiled without errors in Visual Studio 2013 (Version 12.0.31101.00 Update 4)

class A
{
public:
   A(){}
   A(A &&){}
};

int main(int, char*)
{
   A a;
   new A(a);
   return 0;
}

while it is compiled with this error in Visual Studio 2015 RC (Version 14.0.22823.1 D14REL):

1>------ Build started: Project: foo, Configuration: Debug Win32 ------
1>  foo.cpp
1>c:devfoofoo.cpp(11): error C2280: 'A::A(const A &)': attempting to reference a deleted function
1>  c:devfoofoo.cpp(6): note: compiler has generated 'A::A' here
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I think that the compiler shipped with Visual Studio 2015 generates the Copy Constructor and marks it as =delete and so I get the error C2280 (which, by the way, I cannot find documented on msdn.microsoft.com).

Now, let’s say I have a codebase which is compilable with Visual Studio 2013 (and it works because it relies on the code generated automatically by the compiler) but not compilable with Visual Studio 2015 due to C2280, how can I fix the problem?

I was thinking to declare class A in this way:

class A
{
public:
   A(){}
   A(A &&){}
   A(const A&)=default;
};

am I missing something?

asked Jul 7, 2015 at 9:37

Alessandro Jacopson's user avatar

2

From [class.copy]/7, emphasis mine:

If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly.
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy
constructor is defined as deleted
; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if
the class has a user-declared copy assignment operator or a user-declared destructor.

There is an equivalent section with similar wording for copy assignment in paragraph 18. So your class is really:

class A
{
public:
   // explicit
   A(){}
   A(A &&){}

   // implicit
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};

which is why you can’t copy-construct it. If you provide a move constructor/assignment, and you still want the class to be copyable, you will have to explicitly provide those special member functions:

    A(const A&) = default;
    A& operator=(const A&) = default;

You will also need to declare a move assignment operator. If you really have a need for these special functions, you will also probably need the destructor. See Rule of Five.

answered Jul 7, 2015 at 10:38

Barry's user avatar

I had the same problem and it was due to a poorly defined member variable:

double const deltaBase = .001;

Putting this in will cause the copy constructor to be deleted. Get rid of the «const» and assign in the constructor.

answered May 30, 2016 at 3:14

doby's user avatar

dobydoby

5354 silver badges9 bronze badges

3

I encountered the same error, just because I had misused std::unique_ptr.

Note that std::unique_ptr is non-copyable, it is only moveable.

Here is the wrong demonstration.

class word;
class sentence
{
    public:
        sentence();
        ~sentence();

    public:
        // Wrong demonstration, because I pass the parameter by value/copying
        // I should use 'std::shared_ptr< word >' instead.
        sentence(std::initializer_list< std::unique_ptr< word > > sentence);
};

The following code is taken from MSVC compiler’s STL library. We can see that the copy constructor and copy assignment operator of class unique_ptr are deleted explicitly.

    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

answered Sep 27, 2020 at 15:43

QingJia Wang's user avatar

1

I was stuck with this error even after «default»ing the copy ctor. Turned out, one of my class member (rapidjson’s Document object) was disallowing copy. Changed it to a reference, initialized via a *(new rapidjson::Document()) in the default ctor’s initializer list. Looks like all individual members should also be copy’able in addition to the defaulted copy ctor.

answered Aug 19, 2019 at 13:00

Neelabh Mam's user avatar

Neelabh MamNeelabh Mam

3006 silver badges10 bronze badges

If you write a user-defined move constructor for your class, the copy constructor will be deleted. This is because if a class needs special behaviour for its move constructor, it probably needs some similar behaviour in its copy constructor, so the copy constructor will be deleted to stop you from inadvertently using the default behaviour.

If you want to define your own move constructor and use the default copy constructor, you need to declare it as default, like you suggested in your question:

class A
{
public:
   A(){}
   A(A &&){}
   //I know what I'm doing, compiler, use the default version.
   A(const A&)=default;
};

Note that if you define a custom move constructor, you should think about your assignment operators and destructor as well.

answered Jul 7, 2015 at 9:44

TartanLlama's user avatar

TartanLlamaTartanLlama

63.4k13 gold badges156 silver badges193 bronze badges

1

I ran into a similar situation where I had a hierarchy of classes and a destructor in the base class was declared virtual. In this case, compiler does NOT automatically generate move and copy constructors. So we have to default these in order for compiler to generate the definitions for these methods.

However, I ran into another issue after I defaulted copy and move constructor. I saw that the compiler was still not able to generate copy and move constructors. The reason was the usage of std::atomic member variable in the base class. Since atomic variable are not copy able or movable, the compiler could not generate definitions for copy constructor. This gave me lot of headache and I had to solve the problem using a different method.
See other great answers for similar issue that I faced.

References:
Does a default virtual destructor prevent compiler-generated move operations?

Error with copy constructor/assignment operator for a class which has std::atomic member variable

answered Oct 31, 2019 at 23:35

piyu2cool's user avatar

I faced this issue today and mine was caused by having both std::stringstream and std::ostream as member variables. I initially thought this was caused because I accidentally named one of them as sstream which was the name for the header file <sstreamn> I had included previously.

But changing the name didn’t help, and I had to remove the ostream variable completely for this to work again! then I realized I had declared it incorrectly like this:

std::ostream some_stream;

while it should have been :

...
std::ostream some_stream(&filebuf);

Basically, I was much better off using ofstream instead!

answered Oct 3, 2020 at 12:52

Hossein's user avatar

HosseinHossein

23.9k34 gold badges119 silver badges222 bronze badges

0

Цитата
Сообщение от Masai
Посмотреть сообщение

Хотя что танки, что снаряды созданы аналогично, одинаково переданы в функцию столкновений, у снарядов всё окей, а тут проблема.

Надо увидеть объявления обоих классов, где-то в них есть разница, которая так влияет.
Оператор= может быть недоступен по нескольким причинам, например, константы в качестве данных-членов или ссылки могут к этому привести. Смотреть надо объявления твоих классов.
Если, например, у класса есть константы в качестве данных-членов, то компилятор не предоставляет оператор присваивания по умолчанию, т.к. константам нельзя присваивать (по умолчанию выполняется почленное присваивание для всех data members). Если тебе все-таки нужен оператор присваивания в таком классе, его нужно сделать самостоятельно.

Цитата
Сообщение от Masai
Посмотреть сообщение

в целом пока это всё не оптимально задумано

Оно не «неоптимально», оно просто неверно. Зачем нужно было создавать вообще объект динамически, чтобы потом его по значению положить в вектор?
Все же проще гораздо. И без утечек памяти.

C++
1
2
Bomb bomb(Bomb_image, angle_tower, Vector2f(Body_Corpus.getSize().x, Body_Corpus.getSize().y), pos_x, pos_y, Old_Pos, New_Pos);
Bombs.push_back(bomb);

Цитата
Сообщение от Masai
Посмотреть сообщение

Мне просто не совсем понятно почему она нужна при удаление из вектора.

Это очень просто: при удалении из середины вектора, чтобы заполнить образовавшееся пространство, элементы «сдвигаются». Сдвиг выполняется через копирование и присваивание элементов. Например, удалили третий, всего шесть. Третьему вызывается деструктор, затем на его месте через конструктор копирования создается новый объект на основе четвертого. Для остального «хвостика» будет выполняться присваивание: пятый присваивается четвертому, шестой — пятому, и общее количество уменьшается на 1.

Описанный порядок лишь упрощенный пример того, как может выполняться актуализация данных в векторе после выполнения удаления из середины. В реальности, скорее всего, будет выполнено три присваивания, а деструктор вызовется у бывшего последнего элемента, после присваивания его предпоследнему (в первом варианте пришлось бы вызывать два деструктора: для удаляемого элемента, и для «лишнего» бывшего последнего). А если у данных вектора доступно перемещение (move-assignment), то будет задействовано оно, а не присваивание. Это не меняет сути, впрочем. Будь то копирование, присваивание или перемещение — они будут вызываться при некоторых операциях с вектором, удалении не с конца, добавлении элементов, операции изменения размера и т.п.



0



Я новичок в разработке игр и очень плохо знаком с c ++, но я начал разрабатывать небольшую игру Arkanoid. У меня это было запущено ранее, но после рефакторинга (введение класса ArkanoidGame) он не компилируется, и я не могу понять, почему.

Я получаю ошибку:

d:dropboxdevelopmentgamedevc++arkanoidarkanoidmain.cpp(14): error C2280:
'ArkanoidGame::ArkanoidGame(void)' : attempting to reference a deleted function
d:dropboxdevelopmentgamedevc++arkanoidarkanoidarkanoidgame.h(25) :
compiler has generated 'ArkanoidGame::ArkanoidGame' here

Я просто не понимаю, что это значит, и понятия не имею, что делать, чтобы это исправить.

Я включил рассматриваемые классы:

main.cpp:

#include "ArkanoidGame.h"
int main() {
ArkanoidGame game;
game.init(800, 600);
while (game.isRunning()) {
game.checkInput();
game.checkCollisions();
game.draw();
}
return 0;
}

Arkanoid.h:

#include "Ball.h"#include "Pad.h"#include <SFML/Graphics.hpp>
#include <stdarg.h>
#include <memory>

class ArkanoidGame
{
private:
bool running;
public:
void ArkanoidGame::init(int, int);
bool ArkanoidGame::isRunning();
void ArkanoidGame::checkCollisions();
void ArkanoidGame::checkInput();
void ArkanoidGame::update();
void ArkanoidGame::draw();
sf::RenderWindow* window;
Pad pad;
Ball ball;
};

ArkanoidGame.cpp:

#include "ArkanoidGame.h"
void ArkanoidGame::init(int windowWidth, int windowHeight) {
window = new sf::RenderWindow(sf::VideoMode(windowWidth, windowHeight), "Arkanoid!");
window->setFramerateLimit(60);

ArkanoidGame::running = true;

//Init pad
pad = Pad((float)(windowWidth / 2), (float)(windowHeight - 50));

//Init ball
ball = Ball(0.f, 0.f);
}

template<class T1, class T2> bool intersect(T1& mA, T2& mB) {
return mA.right() >= mB.left() && mA.left() <= mB.right()
&& mA.bottom() >= mB.top() && mA.top() <= mB.bottom();
}

void ArkanoidGame::checkCollisions() {
if (!intersect(pad, ball)) return;

ball.velocity.y = -ball.ballVelocity;

if (ball.x() < pad.x()) {
ball.velocity.x = -ball.ballVelocity;
}
else {
ball.velocity.x = ball.ballVelocity;
}
}

void ArkanoidGame::update() {
//Update positions
pad.update(window->getSize().x);
ball.update(window->getSize().x, window->getSize().y);
}

void ArkanoidGame::draw() {
window->clear(Color::Black);
window->draw(pad.getShape());
window->draw(ball.getShape());
window->display();
}

void ArkanoidGame::checkInput() {
if (Keyboard::isKeyPressed(Keyboard::Key::Escape)) {
running = false;
}
}

bool ArkanoidGame::isRunning() {
return running;
}

10

Решение

Предположительно, либо Pad или же Ball (или оба) не имеет конструктора по умолчанию; поэтому нельзя создать класс, который их содержит. Они должны быть инициализированы с использованием одного из объявленных конструкторов.

Лучшее решение состоит в том, чтобы удалить ваш странный init и замените его конструктором:

ArkanoidGame(int windowWidth, int windowHeight) :
running(true),
window(new ...),
Pad(windowWidth / 2, windowHeight - 50),
Ball(0,0)
{
window->setFramerateLimit(60);
}

int main() {
ArkanoidGame game(800, 600);
// ...
}

Если по какой-то причине вы действительно хотите двухэтапный танец инициализации, вам нужно будет предоставить конструкторы по умолчанию для обоих Pad а также Ball, Я не рекомендовал бы это все же; есть меньше возможностей для ошибок, если объект не может быть создан в недопустимом состоянии.

14

Другие решения

Я думаю, что проблема в том, что либо класс Pad, либо класс Ball не имеют конструктора по умолчанию (у вас есть два члена dtat этих классов в определении класса ArkanoidGame: Pad pad; и Ball ball;)
, В этом случае компилятор определил конструктор по умолчанию класса ArkanoidGame как удаленный (в противном случае он будет некорректным). Однако в первой строке главного

ArkanoidGame game;

вы пытаетесь вызвать конструктор по умолчанию класса ArkanoidGame.

Примите также во внимание, что объявления функций-членов должны иметь безусловные имена в определении класса.
Так, например, это объявление

void ArkanoidGame::init(int, int);

является недействительным. Должен быть

void init(int, int);

5

Вы должны предоставить конструктор для ArkanoidGame. В Arkanoid.h:

ArkanoidGame ();

В Arkanoid.cpp:

ArkanoidGame::ArkanoidGame ()
{
// it is better to initialize members in the constructor,
// although not strictlynecessary
running = false;
}

3

Понравилась статья? Поделить с друзьями:
  • Ошибка c2276 недопустимая операция с выражением привязанной функции члена
  • Ошибка c2259 невозможно создать экземпляр абстрактного класса
  • Ошибка c2238 непредвиденные лексемы перед
  • Ошибка c2220 следующее предупреждение рассматривается как ошибка
  • Ошибка c1206 kia ceed jd