Имеются скромные три строчки плюсового кода, написанные в 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
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
АлександрАлександр
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
αλεχολυτ♦αλεχολυτ
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
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
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
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
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 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
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
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
HosseinHossein
23.9k34 gold badges119 silver badges222 bronze badges
0
Сообщение от Masai
Хотя что танки, что снаряды созданы аналогично, одинаково переданы в функцию столкновений, у снарядов всё окей, а тут проблема.
Надо увидеть объявления обоих классов, где-то в них есть разница, которая так влияет.
Оператор= может быть недоступен по нескольким причинам, например, константы в качестве данных-членов или ссылки могут к этому привести. Смотреть надо объявления твоих классов.
Если, например, у класса есть константы в качестве данных-членов, то компилятор не предоставляет оператор присваивания по умолчанию, т.к. константам нельзя присваивать (по умолчанию выполняется почленное присваивание для всех data members). Если тебе все-таки нужен оператор присваивания в таком классе, его нужно сделать самостоятельно.
Сообщение от Masai
в целом пока это всё не оптимально задумано
Оно не «неоптимально», оно просто неверно. Зачем нужно было создавать вообще объект динамически, чтобы потом его по значению положить в вектор?
Все же проще гораздо. И без утечек памяти.
C++ | ||
|
Сообщение от 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