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::stringstream
和 std::ostream
作为成员变量引起的。我最初认为这是因为我不小心将其中一个命名为 sstream
,这是我之前包含的头文件 <sstreamn>
的名称。
但是更改名称没有帮助,我不得不完全删除 ostream
变量才能再次使用!然后我意识到我像这样错误地声明了它:
std::ostream some_stream;
本来应该是:
...
std::ostream some_stream(&filebuf);
基本上,我最好改用 ofstream
!
此代码段在 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::stringstream
和 std::ostream
作为成员变量引起的。我最初认为这是因为我不小心将其中一个命名为 sstream
,这是我之前包含的头文件 <sstreamn>
的名称。
但是更改名称没有帮助,我不得不完全删除 ostream
变量才能再次使用!然后我意识到我像这样错误地声明了它:
std::ostream some_stream;
本来应该是:
...
std::ostream some_stream(&filebuf);
基本上,我最好改用 ofstream
!