繁体   English   中英

auto a = A(3)和A a(3)有什么区别?

[英]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); 足够了。

您为什么期望两个代码路径都相同?

显然,在第二个示例中,您正在构造一个未命名的对象,分配aauto a ),然后将其从临时对象复制到a (这是一个步骤,因为我们正在谈论临时对象)。

两种情况下编译器都将生成相同的代码无关紧要,因为在编译时需要定义必要的函数/构造函数。 这样想吧-优化将在编译/代码解析之后进行,但最终在这种情况下,代码(应该)是相同的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM