简体   繁体   English

C2280:尝试引用已删除的函数(union,struct,copy constructor)

[英]C2280: attempting to reference a deleted function (union, struct, copy constructor)

I have a problem with misleading error messages, when I try to compile the following minimal sample in Visual Studio 2015: 当我尝试在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;
}

I got the following error messages: 我收到以下错误消息:

1>...main.cpp(56): error C2280: 'Rect &Rect::operator =(const Rect &)': attempting to reference a deleted function 1> ... main.cpp(56):错误C2280:'Rect&Rect :: operator =(const Rect&)':尝试引用已删除的函数

1>...main.cpp(50): note: compiler has generated 'Rect::operator =' here 1> ... main.cpp(50):注意:编译器在这里生成了'Rect :: operator ='

The compiler tries to tell me that, the copy constructor of class Rect is a deleted function. 编译器试图告诉我,类Rect的复制构造函数是一个已删除的函数。 So I tried to add all kinds of additional (copy) constructors and assignment operators like shown below but without success: 所以我尝试添加各种附加(复制)构造函数和赋值运算符,如下所示,但没有成功:

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

I recognized that the error actually is not caused in the Rect class. 我认识到错误实际上不是在Rect类中引起的。 When I comment the line 当我评论这条线

Vector& operator = (const Vector& v) { x = v.x; y = v.y; return *this; }

the error disappiers and when I want to keep this line, I have to add the following line: 错误令人失望,当我想保留这一行时,我必须添加以下行:

Vector(Vector&&) = default;

However, this problem seems to show up only if I am using unions and structs inside my Rect class. 但是,只有当我在Rect类中使用联合和结构时,这个问题才会出现。 So I do not know, where my error is actually caused or if just the error message points to the wrong class. 所以我不知道,我的错误实际上是在哪里造成的,或者只是错误消息指向了错误的类。

Repeating the error message: 重复错误消息:

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

This is fairly clear: the member function operator= with parameter const Rect & has been delete d, but your code tries to call it on the line test = Rect(); 这很清楚:成员函数operator= with参数const Rect &已被delete d,但是你的代码试图在行test = Rect(); .

You then say: 然后你说:

The compiler tries to tell me that, the copy constructor of class Rect is a deleted function 编译器试图告诉我,类Rect的复制构造函数是一个已删除的函数

However, you misread the error. 但是,您误读了错误。 The error is about the function operator = , which is called copy assignment operator . 错误是关于函数operator = ,它被称为复制赋值运算符 This is a different function to copy constructor , which would look like Rect::Rect(const Rect &) . 这是复制构造函数的不同函数,它看起来像Rect::Rect(const Rect &)


You say that you tried adding: 你说你试过添加:

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

However this would make no difference. 然而,这没有任何区别。 The compiler-generated operator= function is delete d because it is not possible for the compiler to generate one (explanation for this comes below); 编译器生成的operator=函数是delete d,因为编译器不可能生成一个(下面对此进行解释); writing = default; 写作= default; does not change this. 不会改变这一点。 You have to actually write your own body for operator= which performs the actions that you want to occur when an assignment happens. 您必须为operator=实际编写自己的主体,它执行您在分配发生时要执行的操作。


In Standard C++ it is not permitted to have an anonymous struct, let alone an anonymous struct inside an anonymous union. 在标准C ++中,不允许使用匿名结构,更不用说匿名结合中的匿名结构。 So you are really out on your own here. 所以你真的在这里独自一人。 The rules your compiler is using regarding operator= , copy constructor, etc. are not covered by any Standard. 编译器使用的有关operator= ,copy构造函数等的规则不受任何标准的约束。

A version of your Rect that is compilable in Standard C might look like: 可在标准C中编译的Rect版本可能如下所示:

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) {}
};

So far, so good. 到现在为止还挺好。 For this class, the implicitly-declared operator= is defined as deleted . 对于此类,隐式声明的operator=定义为已删除 To see why , we first have to look at the implicitly-declared special functions for the anonymous union, because the behaviour of implicitly-declared function for a class depends on the behaviour of the same operation for each of its members. 为了了解原因,我们首先要查看匿名联合的隐式声明的特殊函数,因为类的隐式声明函数的行为取决于每个成员的相同操作的行为。

The relevant rule here for the union is C++14 [class.union]/1: 联合的相关规则是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 delete d for the union. 如果联合的任何非静态数据成员具有非平凡的默认构造函数,复制构造函数,移动构造函数,复制赋值运算符,移动赋值运算符或析构函数,则联合的相应成员函数必须是用户提供的,否则它将为联盟隐式delete d。

Vector has a non-trivial operator= , because you write your own body for it. Vector有一个非平凡的operator= ,因为你为它编写了自己的主体。 Therefore S1 has non-trivial operator= , because it has a member with non-trivial operator= , and so according to the above quote, the implicitly-declared operator= for the union is delete d. 因此S1具有非平凡的operator= ,因为它具有非平凡的operator=的成员,因此根据上面的引用,对于union的隐式声明的operator=delete d。

Note that there is no error about the copy-constructor: Vector does have a trivial copy-constructor, so the union does too. 请注意,复制构造函数没有错误: Vector 确实有一个简单的复制构造函数,因此union也是如此。


To fix this error you could do one of two things: 要修复此错误,您可以执行以下两项操作之一:

  • Change Vector::operator= to be trivial, either by removing your definition entirely, or making it = default; 通过完全删除你的定义,或者使它= default; ,将Vector::operator=改变为微不足道的= default;
  • Write operator= for the Rect class operator=Rect

Now, how would you write your own operator= ? 现在,您将如何编写自己的operator= Do you do s1 = other.s1; 你做s1 = other.s1; , or do you do s2 = other.s2; ,或者你做s2 = other.s2; ? The compiler can't know that on its own, which is the reason behind the implicitly-declared operator= being deleted. 编译器无法自己知道,这是隐式声明的operator=被删除的原因。

Now, it seems you overlooked (either accidentally or deliberately) the rule about active members in C++: 现在,您似乎忽略了(无论是偶然还是故意)关于C ++中活动成员的规则:

In a union, at most one of the non-static data members can be active at any time 在联合中,至多一个非静态数据成员可以随时处于活动状态

This means that if s1 is the last member set, then you'd have to do s1 = other.s1; 这意味着如果s1是最后一个成员集,那么你必须做s1 = other.s1; . Or if s2 is the last member set, you'd have to do s2 = other.s2; 或者,如果s2是最后一个成员集,则必须执行s2 = other.s2; .

The copy-constructor doesn't run into this problem because it is trivial : the compiler can generate a bit-wise copy and that will correctly implement the copy regardless of which member was active. 复制构造函数不会遇到这个问题,因为它很简单 :编译器可以生成按位复制,并且无论哪个成员处于活动状态,都能正确实现复制。 But since your operator= is non-trivial, that would not be possible. 但由于你的operator=非常重要,这是不可能的。

For example, imagine if you actually had a union of std::string and std::vector - bitwise copy doesn't work for either of those and you need to know which one is active in order to perform the copy. 例如,假设您实际上有一个std::stringstd::vector - 按位复制不适用于其中任何一个,并且您需要知道哪个是活动的才能执行复制。


Reiterating: In standard C++ it is not permitted to read a member of a union other than the one most recently written to . 重申: 在标准C ++中,不允许读取最近写入的联合的成员 You can't use unions for aliasing. 您不能使用联合进行别名。 C++ has other language tools to achieve what you might do in C with union aliasing, see here for more discussion . C ++有其他语言工具可以实现你在C中使用联合别名做的事情, 请参阅此处以获得更多讨论

Based on the choice of members for your anonymous structs I suspect that this is what you intended to do. 根据您对匿名结构的成员选择,我怀疑这是您打算做的。 If you really want to go ahead with this approach, relying on your compiler implementing union aliasing as a non-standard extension, then my advice would be to use the defaulted operator= for your Vector class. 如果你真的想继续这种方法,依靠你的编译器实现联合别名作为非标准的扩展,那么我的建议是使用默认的operator=为你的Vector类。

The error is from the union placing the memory usage of the floats p1x, ... p2y on top of the allocation for the Vector objects. 错误来自联合将浮点数p1x, ... p2y的内存使用放在Vector对象的分配之上。

g++ would give a more explicit error message informing that an object with a constructor cannot be used in a union. g ++会给出一个更明确的错误消息,告知带有构造函数的对象不能在union中使用。

I'm surprised VS does not report an error on the use of an object in a union directly. 我很惊讶VS没有直接报告在联合中使用对象的错误。 It would be interesting to see what happens if you declare the Vectors AFTER the floats in your union. 如果你在你的联盟中声明了浮动之后会发生什么,那将会很有趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C2280尝试引用已删除的功能 - C2280 attempting to reference a deleted function C2280 = 试图引用已删除的 function - C2280 = attempting to reference a deleted function 错误C2280:尝试引用已删除的功能 - error C2280: attempting to reference a deleted function Qt编译错误:C2280:尝试引用已删除的函数 - Qt compile error: C2280: attempting to reference a deleted function 嵌套联合编译错误:C2280 试图引用已删除的 function - Nested union compilation error: C2280 attempting to reference a deleted function 错误C2280:在声明C ++结构时尝试引用已删除的函数 - error C2280: attempting to reference a deleted function while declaring a C++ struct C ++错误C2280:尝试引用已删除的函数 - C++ Error C2280: Attempting to reference a deleted function 错误C2280:尝试引用已删除的函数(原子 <int> ) - error C2280: attempting to reference a deleted function (atomic<int>) 编译器错误C2280,尝试引用已删除的函数operator = - Compiler error C2280, attempting to reference a deleted function operator= C2280:复制构造函数的“尝试引用引用的已删除函数”,CC248“&#39;operator =&#39;无法访问在类中声明的私有成员”(Cocos2dx) - C2280: “attempting to reference deleted function” for copy constructor, CC248 “'operator ='cannot access private member declared in class” (Cocos2dx)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM