[英]What's the difference between auto a = A(3) and A a(3)?
假设我有:
struct A
{
A(int x) : m_x(x) { }
A(A&&) = delete;
int m_x;
}
和:
A a(3); // Ok
auto a = A(3); // Error: function A(int&&) cannot be referenced - it's a deleted function
后者为何调用move构造函数? 为什么这2条语句在生成代码方面有所不同?
auto a = A(3);
与A a = A(3);
因为右侧的类型是A
这意味着确切的样子: A(3)
创建一个用3
初始化的临时A
,然后A a = _____
意思是:创建a
以_____
作为初始化程序的A
因此,您创建了一个临时文件,将该临时文件传递给a
作为初始化程序,然后销毁了该临时文件。 这种类型的初始化(带有=
)称为复制初始化 (尽管不要将其与“复制”混淆,这只是一个词)。
选择一个构造函数来构造a
接受A
。 它必须是副本或移动构造函数。 A
具有移动构造函数和复制构造函数。 后者是隐式生成的,并且也定义为Deleted,因为有一个用户声明的move构造函数。
但是,被定义为Delete不会影响重载解析; 在这种情况下,move构造函数比copy构造函数更可取。
因此,您的代码尝试调用格式错误的delete
d函数,从而导致错误。
请注意,如果未删除move-constructor,则将应用复制省略。 在某些情况下,它会从临时变量初始化,或者按值返回局部变量。 规则是编译器可以为a
和临时对象使用相同的内存,并忽略对copy / move构造函数的调用。
在大多数情况下,大多数/所有编译器都会这样做。 因此,您实际上可以auto a = A(3);
写auto a = A(3);
并且在实践中不会采取任何不必要的措施。 如果您为移动构造函数编写了一些输出内容的代码,则希望会发现什么都没有输出。
如果要绝对确定没有不必要的副本,或者构造没有可用副本的对象,也不要移动构造函数-停止编写指定不必要副本的代码! A a(3);
足够了。
您为什么期望两个代码路径都相同?
显然,在第二个示例中,您正在构造一个未命名的对象,分配a
( auto a
),然后将其从临时对象复制到a
(这是一个步骤,因为我们正在谈论临时对象)。
两种情况下编译器都将生成相同的代码无关紧要,因为在编译时需要定义必要的函数/构造函数。 这样想吧-优化将在编译/代码解析之后进行,但最终在这种情况下,代码(应该)是相同的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.