在测试某些类时,我遇到了一个有趣的问题:如果使用等号(=)调用类构造函数(如果删除了复制构造函数),则会遇到错误错误:类型为“ Class”的复制变量会调用删除构造函数。使用括号时,代码可以正常编译。
这是怎么回事?这可以是编译器错误吗?
请考虑以下课程:
class Test
{
public:
int Int;
public:
Test() = default;
Test(Test &) = delete;
Test(Test &&) = delete;
Test(int i)
{
Int = i;
}
};
构造函数的调用方式如下:
Test t1(3); //No error
Test t2 = 3; //error: copying variable of type 'Class' invokes deleted constructor
仅检查一下,我试图添加一些检查并允许这些功能和编译代码。 两个构造函数都以完全相同的方式使用MSVC 进行编译。
class Test
{
public:
int Int;
public:
Test()
{
Int = 0;
cout << "Constructor";
}
Test(Test &t)
{
Int = t.Int;
cout << "Copy Constructor";
}
Test(Test &&t)
{
Int = t.Int;
cout << "Move Constructor";
}
Test(int i)
{
Int = i;
cout << "Constructor from int";
}
};
Test t1(3); //Constructor from int
Test t2 = 3; //Constructor from int
这到底是怎么回事?
答案 0 :(得分:1)
您正在看到copy elision规则的结果。
基本上,说T var = expr;
从expr
构造一个未命名的临时文件,然后使用复制或移动构造器将其复制或移动到var
中。如果复制和移动构造函数被删除,则将给出有关已删除构造函数的错误。但是,然后需要编译器直接从var
中删除复制或移动并构造expr
,即使复制或移动构造函数具有明显的副作用。它是由语言设计引起的那些奇怪的极端情况之一,这些语言是通过对不同实现的实际作用(或过去某个时候所做的事情)进行事实上的标准化,加上按委员会设计和随着时间的推移缓慢发展,同时试图保持向后兼容
see here进行更多讨论