C++ 编译器错误 C2280“试图引用已删除的函数"在 Visual Studio 2013 和 2015 中

2021-12-22 00:00:00 visual-c++ c++ copy-constructor c++14

此代码段在 Visual Studio 2013(版本 12.0.31101.00 更新 4)中编译没有错误

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

在 Visual Studio 2015 RC(版本 14.0.22823.1 D14REL)中编译时出现此错误:

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:devfoofoo.cpp(11): error C2280: 'A::A(const A &)': attempting to reference a deleted function
1>  c:devfoofoo.cpp(6): note: compiler has generated 'A::A' here
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

我认为 Visual Studio 2015 附带的编译器生成复制构造函数并将其标记为 =delete,因此我收到错误 C2280(顺便说一下,我在 msdn.microsoft.com).

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).

现在,假设我有一个可以用 Visual Studio 2013 编译的代码库(它可以工作,因为它依赖于编译器自动生成的代码)但由于 C2280 而不能用 Visual Studio 2015 编译,我该如何修复问题?

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?

我想以这种方式声明 A 类:

I was thinking to declare class A in this way:

class A
{
public:
   A(){}
   A(A &&){}
   A(const A&)=default;
};

我错过了什么吗?

推荐答案

来自 [class.copy]/7,强调我的:

From [class.copy]/7, emphasis mine:

如果类定义未显式声明复制构造函数,则隐式声明非显式.如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的副本构造函数定义为删除;否则,它被定义为默认(8.4).后一种情况被弃用,如果该类具有用户声明的复制赋值运算符或用户声明的析构函数.

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.

在第 18 段中有一个具有相似措辞的副本分配的等效部分.所以你的班级真的是:

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.

相关文章