C2280 error attempint to reference a deleted function

629 Views Asked by At

The function DataContainer.initial() triggers a C2280 error. After defining a move assignment operator it works. But I am not clear why in function initial_2() it works. The obvious difference is that data_a is a local variable and data_b is a class member. Thanks for helping.

#include <vector>
#include <iostream>

class DataTypeA
{
    std::vector<double> data;
public:
    // default constructor
    DataTypeA() {}

    // Move constructor
    DataTypeA(DataTypeA&& rhs) noexcept :data(std::move(rhs.data))
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    //DataTypeA& operator=(TypeB&& rhs) noexcept
    //{
    //  data = (std::move(rhs.data));
    //  return *this;
    //}

    DataTypeA(size_t width, size_t height, double default_val)  { data.resize(width * height, default_val); }

    size_t get_size() const { return data.size(); }
};

class Reader 
{
public:
    Reader() {}

    DataTypeA read_data()
    {
        DataTypeA rtn(5, 5, 1.2);
        return rtn;
    }
};

class DataContainer
{
    DataTypeA data_b;
public:
    DataContainer() {}

    void initial()
    {
        Reader rd;
        
        // this requires the copy or move assignment operator
        // Error C2280  'DataTypeA &DataTypeA::operator =(const DataTypeA &)': attempting to reference a deleted function   
        data_b = rd.read_data();
    }

    void initial_2()
    {
        Reader rd;
        DataTypeA data_a = rd.read_data();
        std::cout << data_a.get_size();
    }
};
2

There are 2 best solutions below

0
pigrammer On BEST ANSWER

In the function initial_2, you are creating a new object of type DataTypeA from an existing object, so you can use the move constructor. However, in initial, you are assigning new data to an existing object. For this, you need to have the assignment operator. See Difference between the move assignment operator and move constructor?.

2
Vlad from Moscow On

As you explicitly declared the move constructor then the implicitly declared copy and move assignment operators defined as deleted.

From the C++ 17 Standard (15.8.2 Copy/move assignment operator)

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

and

4 If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if

(4.1) — X does not have a user-declared copy constructor,

(4.2) — X does not have a user-declared move constructor,

(4.3) — X does not have a user-declared copy assignment operator, and

(4.4) — X does not have a user-declared destructor.

And in this statement

data_b = rd.read_data();

there must be used an assignment operator (either the copy or move assignment operator depending on which is defined) that is according to the quotes is deleted.

As for this record

DataTypeA data_a = rd.read_data();

then it is a declaration. So there is used a constructor.