jjzjj

c++ - C2280 : attempting to reference a deleted function (union, 结构体,复制构造函数)

coder 2024-02-04 原文

当我尝试在 Visual Studio 2015 中编译以下最小示例时,我遇到了误导性错误消息的问题:

class Vector
{
    float x;
    float y;

public:

    Vector(float x, float y) : x(x), y(y) {}
    Vector& operator = (const Vector& v) { x = v.x; y = v.y; return *this; }
    //Vector(Vector&&) = default;
};


class Rect
{
public:
    union {
        struct {
            Vector p1, p2;
        };

        struct {
            float p1x, p1y, p2x, p2y;
        };
    };

    Rect() : p1(0,0),  p2(0,0) {}
    Rect(Vector& p1,  Vector& p2) : p1(p1), p2(p2) {}

    /*Rect(const Rect&) = default;
    Rect& operator=(const Rect&) = default;
    Rect& operator=(Rect&&) = default;
    Rect(Rect&&) = default;*/
};


int main()
{
    Rect test = Rect();
    test = Rect();
    return 0;
}
我收到以下错误消息:

1>...main.cpp(56): error C2280: 'Rect &Rect::operator =(const Rect &)': attempting to reference a deleted function

1>...main.cpp(50): note: compiler has generated 'Rect::operator =' here


编译器试图告诉我,类 Rect 的复制构造函数是一个被删除的函数。所以我尝试添加各种额外的(复制)构造函数和赋值运算符,如下所示,但没有成功:
Rect(const Rect&) = default;
Rect& operator=(const Rect&) = default;
Rect& operator=(Rect&&) = default;
Rect(Rect&&) = default;
我认识到错误实际上不是由 Rect 类引起的。当我评论该行时
Vector& operator = (const Vector& v) { x = v.x; y = v.y; return *this; }
错误消失了,当我想保留这一行时,我必须添加以下行:
Vector(Vector&&) = default;
然而,这个问题似乎只有当我在我的 Rect 类中使用 union 和结构时才会出现。
所以我不知道,我的错误实际上是在哪里引起的,或者只是错误消息指向了错误的类。

最佳答案

重复错误信息:

main.cpp(56): error C2280: 'Rect &Rect::operator =(const Rect &)': attempting to reference a deleted function



这很清楚:成员函数 operator=带参数 const Rect &delete d,但您的代码尝试在行 test = Rect(); 上调用它.

然后你说:

The compiler tries to tell me that, the copy constructor of class Rect is a deleted function



但是,您误读了错误。错误是关于函数 operator = ,称为复制赋值运算符。这是一个与复制构造函数不同的函数,它看起来像 Rect::Rect(const Rect &) .

你说你尝试添加:

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



然而,这不会有什么区别。编译器生成 operator=功能是 delete d 因为编译器不可能生成一个(对此的解释如下);写作 = default;不会改变这一点。你必须真正为 operator= 写你自己的 body 它执行您希望在分配发生时发生的操作。

在标准 C++ 中,不允许有匿名结构,更不用说匿名 union 中的匿名结构了。所以你真的是一个人在这里。您的编译器使用的关于 operator= 的规则、复制构造函数等不在任何标准中。

您的一个版本 Rect在标准 C 中可编译的内容可能如下所示:
class Rect
{
public:
    struct S1 {
        Vector p1, p2;
        S1(Vector p1, Vector p2): p1(p1), p2(p2) {} 
    };
    struct S2 {
        float p1x, p1y, p2x, p2y;
    };

    union {
        struct S1 s1;
        struct S2 s2;
    };

    Rect() : s1({0, 0}, {0, 0}) {}
    Rect(Vector p1,  Vector p2) : s1(p1, p2) {}
};

到现在为止还挺好。对于此类,隐式声明的 operator=定义为删除。要了解原因,我们首先必须查看匿名 union 的隐式声明的特殊函数,因为类的隐式声明函数的行为取决于对其每个成员的相同操作的行为。

union 的相关规则是 C++14 [class.union]/1:

If any non-static data member of a union has a non-trivial default constructor , copy constructor, move constructor, copy assignment operator, move assignment operator, or destructor, the corresponding member function of the union must be user-provided or it will be implicitly deleted for the union.


Vector有一个不平凡的operator= ,因为你为它写了你自己的 body 。因此 S1有不平凡的operator= ,因为它有一个非平凡的成员 operator= ,因此根据上面的引用,隐式声明的 operator= union 是 delete d.

请注意,复制构造函数没有错误:Vector确实有一个简单的复制构造函数,所以 union 也有。

要修复此错误,您可以执行以下两项操作之一:
  • 更改 Vector::operator=变得微不足道,要么完全删除您的定义,要么使其成为= default;
  • 写信 operator=Rect类(class)

  • 现在,您将如何编写自己的 operator= ?你做吗s1 = other.s1; ,或者你做s2 = other.s2; ?编译器自己无法知道,这就是隐式声明 operator= 背后的原因。被删除。

    现在,您似乎忽略了(无意或有意)C++ 中有关事件成员的规则:

    In a union, at most one of the non-static data members can be active at any time



    这意味着如果 s1是最后一个成员集,那么你必须做 s1 = other.s1; .或者如果 s2是最后一个成员集,你必须做 s2 = other.s2; .

    复制构造函数不会遇到这个问题,因为它是微不足道的:编译器可以生成一个按位的拷贝,并且无论哪个成员处于事件状态,它都会正确地实现该拷贝。但是由于您的 operator=是非平凡的,那是不可能的。

    例如,假设您实际上有一个 union std::stringstd::vector - 按位复制对其中任何一个都不起作用,您需要知道哪个是事件的才能执行复制。

    重申:在标准 C++ 中,除了最近写入 的成员之外,不允许读取 union 成员。 .您不能将 union 用于别名。 C++ 有其他语言工具可以使用 union 别名实现您在 C 中所做的事情,see here for more discussion .

    根据您为匿名结构选择的成员,我怀疑这就是您打算做的。如果你真的想继续使用这种方法,依靠你的编译器将 union 别名作为非标准扩展来实现,那么我的建议是使用默认的 operator=为您 Vector类(class)。

    关于c++ - C2280 : attempting to reference a deleted function (union, 结构体,复制构造函数),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33921710/

    有关c++ - C2280 : attempting to reference a deleted function (union, 结构体,复制构造函数)的更多相关文章

    1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

      我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

    2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    3. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

      给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

    4. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    5. ruby-on-rails - 一般建议和推荐的文件夹结构 - Sinatra - 2

      您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应

    6. ruby - 如何计算 Liquid 中的变量 +1 - 2

      我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

    7. arrays - Ruby 数组 += vs 推送 - 2

      我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

    8. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

      我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

    9. += 的 Ruby 方法 - 2

      有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

    10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

      出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

    随机推荐