Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Compiler Error C2280 "attempting to reference a deleted function" in Visual Studio 2013 and 2015

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:\dev\foo\foo.cpp(11): error C2280: 'A::A(const A &)': attempting to reference a deleted function
1>  c:\dev\foo\foo.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?

like image 805
Alessandro Jacopson Avatar asked Jul 07 '15 09:07

Alessandro Jacopson


4 Answers

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.

like image 122
Barry Avatar answered Nov 05 '22 16:11

Barry


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.

like image 39
doby Avatar answered Nov 05 '22 15:11

doby


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.

like image 5
Neelabh Mam Avatar answered Nov 05 '22 15:11

Neelabh Mam


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;
like image 5
QingJia Wang Avatar answered Nov 05 '22 17:11

QingJia Wang