Visual Studio 2013 和 2015 中的 C++ 编译器错误 C2280 "attempting to reference a deleted function"

C++ Compiler Error C2280 "attempting to reference a deleted function" in Visual Studio 2013 and 2015

此代码段在 Visual Studio 2013(版本 12.0.31101.00 更新 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)中编译时出现此错误:

1>------ Build started: Project: foo, Configuration: Debug Win32 ------
1>  foo.cpp
1>c:\dev\foo\foo.cpp(11): error C2280: 'A::A(const A &)': attempting to reference a deleted function
1>  c:\dev\foo\foo.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).

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

我想这样声明classA:

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

我是不是漏了什么?

如果您为 class 编写用户定义的移动构造函数,复制构造函数将被删除。这是因为如果 class 的移动构造函数需要特殊行为,它的复制构造函数可能需要一些类似的行为,因此将删除复制构造函数以防止您无意中使用默认行为。

如果您想定义自己的移动构造函数 使用默认的复制构造函数,您需要将其声明为 default,就像您在问题中建议的那样:

class A
{
public:
   A(){}
   A(A &&){}
   //I know what I'm doing, compiler, use the default version.
   A(const A&)=default;
};

请注意,如果您定义自定义移动构造函数,您还应该考虑您的赋值运算符和析构函数。

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

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 段中有一个具有类似措辞的等效部分用于复制分配。因此您的 class 实际上是:

class A
{
public:
   // explicit
   A(){}
   A(A &&){}

   // implicit
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};

这就是为什么你不能复制构造它的原因。如果您提供移动 constructor/assignment,并且您仍然希望 class 可复制,则必须显式提供那些特殊的成员函数:

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

您还需要声明一个移动赋值运算符。如果您真的需要这些特殊功能,您可能还需要析构函数。参见 Rule of Five

我遇到了同样的问题,这是由于成员变量定义不当造成的:

double const deltaBase = .001;

放入这个会导致复制构造函数被删除。摆脱 "const" 并在构造函数中分配。

即使在 "default" 复制 ctor 之后,我仍然遇到这个错误。原来,我的 class 成员之一(rapidjson 的文档对象)不允许复制。将其更改为引用,通过默认 ctor 的初始化列表中的 *(new rapidjson::Document()) 进行初始化。看起来除了默认的复制 ctor 之外,所有个人成员也应该是可复制的。

我 运行 遇到了类似的情况,我有一个 classes 的层次结构,并且基 class 中的析构函数被声明为虚拟的。在这种情况下,编译器不会自动生成移动和复制构造函数。所以我们必须默认这些,以便编译器生成这些方法的定义。

但是,在默认复制和移动构造函数后,我 运行 陷入了另一个问题。我看到编译器仍然无法生成复制和移动构造函数。原因是在基 class 中使用了 std::atomic 成员变量。由于原子变量不可复制或移动,编译器无法生成复制构造函数的定义。这让我很头疼,我不得不使用不同的方法来解决问题。 查看我遇到的类似问题的其他很好的答案。

参考资料:

Error with copy constructor/assignment operator for a class which has std::atomic member variable

我遇到了同样的错误,只是因为我误用了std::unique_ptr。

注意std::unique_ptr是non-copyable,只能移动

这里是错误的演示。

class word;
class sentence
{
    public:
        sentence();
        ~sentence();

    public:
        // Wrong demonstration, because I pass the parameter by value/copying
        // I should use 'std::shared_ptr< word >' instead.
        sentence(std::initializer_list< std::unique_ptr< word > > sentence);
};

以下代码取自MSVC编译器的STL库。我们可以看到classunique_ptr的拷贝构造函数和拷贝赋值运算符被显式删除

    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

我今天遇到了这个问题,我的问题是由于将 std::stringstreamstd::ostream 作为成员变量引起的。我最初认为这是因为我不小心将其中一个命名为 sstream,这是我之前包含的头文件 <sstreamn> 的名称。

但是更改名称没有帮助,我不得不完全删除 ostream 变量才能再次使用!然后我意识到我像这样错误地声明了它:

std::ostream some_stream;

本来应该是:

...
std::ostream some_stream(&filebuf);

基本上,我最好改用 ofstream