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

Ale*_*son 29 c++ copy-constructor visual-c++ c++14

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

class A
{
public:
   A(){}
   A(A &&){}
};

int main(int, char*)
{
   A a;
   new A(a);
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

虽然它在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 ==========
Run Code Online (Sandbox Code Playgroud)

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

现在,假设我有一个可与Visual Studio 2013兼容的代码库(它可以工作,因为它依赖于编译器自动生成的代码)但由于C2280而无法与Visual Studio 2015进行编译,我该如何解决这个问题呢?

我想以A这种方式宣布课:

class A
{
public:
   A(){}
   A(A &&){}
   A(const A&)=default;
};
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?

Bar*_*rry 40

从[class.copy]/7开始,强调我的:

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

对于第18段中的副本分配,有一个相同的部分具有相似的措辞.所以你的课程确实是:

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

   // implicit
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

这就是为什么你不能复制它的原因.如果提供移动构造函数/赋值,并且仍希望该类可复制,则必须显式提供这些特殊的成员函数:

    A(const A&) = default;
    A& operator=(const A&) = default;
Run Code Online (Sandbox Code Playgroud)

您还需要声明一个移动赋值运算符.如果您真的需要这些特殊功能,您可能还需要析构函数.见五法则.


小智 25

我有同样的问题,这是由于一个定义不明确的成员变量:

double const deltaBase = .001;
Run Code Online (Sandbox Code Playgroud)

将其放入将导致复制构造函数被删除.摆脱"const"并在构造函数中赋值.

  • 在这里也是一样,除了我有一个未设置的引用并遇到了这个问题:Foo& foo; (2认同)
  • 我也遇到了这个错误,但我仍然不明白为什么 const 会导致复制构造函数被删除。 (2认同)

小智 8

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

请注意, std::unique_ptr 是不可复制的,它只能移动。

这是错误的演示。

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);
};
Run Code Online (Sandbox Code Playgroud)

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

    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
Run Code Online (Sandbox Code Playgroud)


Tar*_*ama 5

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

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

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

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


小智 5

即使在“默认”复制向量之后,我仍然遇到这个错误。事实证明,我的一名班级成员(rapidjson 的 Document 对象)不允许复制。将其更改为引用,通过默认构造函数的初始值设定项列表中的 *(newrapidjson::Document()) 进行初始化。看起来除了默认的复制者之外,所有个人成员也应该是可复制的。