我有一个框架,它将异常定义为不可复制的类,我们从中派生出可复制的类(定义复制构造函数调用不可复制的基类构造函数)
这适用于 g++,但不适用于 MSVC 2013。
以下代码将重现该问题:
#include <iostream>
using namespace std;
#if defined _MSC_VER
#define __PRETTY_FUNCTION__ __FUNCTION__
#endif
class u {
u(const u&) = delete;
const u& operator=(const u&) = delete;/* the library we use defines it as const u& */
public:
u() { cout << __PRETTY_FUNCTION__ << "def" << endl; }
protected:
explicit u(int i) { cout << __PRETTY_FUNCTION__ << "int: " << i << endl; }
};
class e : public u {
public:
e() { cout << __PRETTY_FUNCTION__ << "def" << endl; }
e(const e& _e) : u(1) { cout << __PRETTY_FUNCTION__ << "cpy" << endl; }
e& operator=(const e& _e) { cout << __PRETTY_FUNCTION__ << endl; return *this; }
};
int foo() {
e _e;
throw _e;
return 0;
}
int main() {
try {
foo();
} catch(const e& _e) {
cout << "in catch e" << endl;
} catch(...) {
cout << "in catch..." << endl;
}
#if defined _MSC_VER
cout << "press enter to exit" << endl;
cin.get();
#endif
return 0;
}
MSVC 提示 Error 1 error C2280: 'u::u(const u &)' : 试图在函数 foo() 的末尾引用已删除的函数
。
g++ 和 clang 都编译代码,它们根本不使用复制构造函数(e 对象被移动),但如果 e
不是可复制构造的,它们都不会编译。
编辑:我已编辑代码以强制复制。
顺便说一句,如果 u
复制函数没有被删除(也没有定义,c++11 之前不可复制),MSVC 在 u::u(const u&)
查找。 ( Unresolved external )
是我的代码有缺陷,还是 MSVC 中有这个错误?
最佳答案
首先,e
和 u
都有用户声明的复制构造函数。这意味着它们没有隐式生成的移动构造函数或移动赋值运算符。 (因此,您声称“e
对象已被移动”是错误的;更多内容请参见下文)。
e
是可复制的,u
是不可复制的。 e
被认为是 movable,因为如果没有 move-constructor,移动会退回到复制。
根据C++14的[except.throw]节(C++11也是一样),抛出异常时的对象初始化等价于:
e temp = e_; // (1)
const e& _e = temp; // (2)
对于(1),没有创建临时的,因为 e_
和 temp
具有相同的类型。
对于(2)是直接绑定(bind):_e
直接引用temp
,不再临时。
您可能还记得 (1) 是 copy elision语境。这意味着必须存在可访问的拷贝或移动构造函数;但允许编译器跳过对该构造函数的调用,并为两个对象使用相同的内存空间。
这可能就是您所说的“e
对象已移动”的意思:您看到它没有被复制,但实际上它是复制省略时假设移动。
把它们放在一起:throw
- catch
工作的唯一要求是 e
有一个可调用的移动构造函数或复制-构造函数。 (这个构造函数可能实际上没有被调用,但它必须存在)。
您的 e
实际上确实有一个可调用的复制构造函数,因此代码是正确的,并且您尝试的 MSVC 版本存在错误。
如果您仍然可以访问该版本,那么尝试实际编写 e temp = e_; 会很有趣。 const e& _e = temp;
并查看该代码是否生成相同的错误消息。这将显示该错误是否与编译器的 copy-initialization 实现有关,而不是其抛出的错误。
关于c++ - 抛出派生自不可复制的可复制类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29564370/