C2280 尝试引用已删除函数时出错 [duplicate]

C2280 error attempint to reference a deleted function [duplicate]

提问人:stevenhz 提问时间:10/17/2022 更新时间:10/17/2022 访问量:454

问:

这个问题在这里已经有答案了:
去年关闭。

社区去年审查了是否重新讨论这个问题,并关闭了它:

原始关闭原因未解决

函数 DataContainer.initial() 触发 C2280 错误。定义移动分配运算符后,它就可以工作了。但我不清楚为什么它在功能上有效。明显的区别是,它是一个局部变量,是一个类成员。谢谢你的帮助。initial_2()data_adata_b

#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();
    }
};
C++ 移动 deleted-functions

评论

0赞 UnholySheep 10/17/2022
尽管语法相似,但这两行执行不同的事情。 是初始化,是赋值DataTypeA data_a = rd.read_data();data_b = rd.read_data();
1赞 463035818_is_not_an_ai 10/17/2022
阅读完整的错误消息。错误号“C2280”是相当无用的,但完整的错误消息应该包含有价值的信息。例如,gcc 会说出您需要知道的所有信息 godbolt.org/z/x7bvGocez
0赞 user12002570 10/17/2022
欺骗:C++ 编译器错误 C2280“尝试引用已删除的函数”。参考如何询问“搜索然后研究”的第一步在哪里,你会发现很多相关的 SO 帖子。

答:

2赞 pigrammer 10/17/2022 #1

在函数中,您将从现有对象创建类型的新对象,因此可以使用移动构造函数。但是,在 中,您正在将新数据分配给现有对象。为此,您需要具有赋值运算符。请参见移动赋值运算符和移动构造函数之间的区别?initial_2DataTypeAinitial

0赞 Vlad from Moscow 10/17/2022 #2

当您显式声明移动构造函数时,隐式声明的复制和移动赋值运算符将定义为已删除。

从 C++ 17 标准(15.8.2 复制/移动赋值运算符)

2 如果类定义未显式声明副本 赋值运算符,一个是隐式声明的。如果类 definition 声明 Move 构造函数或 Move 赋值运算符, 隐式声明的复制赋值运算符定义为 已删除;否则,它被定义为默认值 (11.4)。后一种情况 如果类具有用户声明的 copy 构造函数或 用户声明的析构函数。隐式声明的副本分配 类 X 的运算符将具有以下形式

4 如果类 X 的定义没有显式声明移动 赋值运算符,如果出现以下情况,则 one 将被隐式声明为默认值 并且仅当

(4.1) — X 没有用户声明的复制构造函数,

(4.2) — X 没有用户声明的移动构造函数

(4.3) — X 没有用户声明的复制分配运算符,并且

(4.4) — X 没有用户声明的析构函数。

在这份声明中

data_b = rd.read_data();

必须使用赋值运算符(复制或移动赋值运算符,具体取决于定义的赋值运算符),即根据引号被删除。

至于这个记录

DataTypeA data_a = rd.read_data();

那么它就是一个宣言。所以使用了一个构造函数。

评论

0赞 Alex 10/17/2022
您可以将其关闭为重复,而不是重复并将相同的内容从一个答案复制粘贴到另一个答案。这有很多重复。
0赞 463035818_is_not_an_ai 10/17/2022
@Ronald这不是从另一个答案复制而来的。如果是,您应该提供一个链接。复述其他地方已经存在的东西和没有适当参考的普通副本,这将是剽窃,是两个完全不同的故事。