简体   繁体   English

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

[英]What's the difference between auto a = A(3) and A a(3)?

Suppose I have: 假设我有:

struct A
{
    A(int x) : m_x(x) { }
    A(A&&) = delete;
    int m_x;
}

and: 和:

A a(3); // Ok
auto a = A(3); // Error: function A(int&&) cannot be referenced - it's a deleted function

Why does the latter call to the move constructor? 后者为何调用move构造函数? Why are these 2 statement different in terms of generated code? 为什么这2条语句在生成代码方面有所不同?

auto a = A(3); means the same as A a = A(3); A a = A(3); since the type of the right hand side is A . 因为右侧的类型是A

This means exactly what it looks like: A(3) creates a temporary A initialized with 3 , and then A a = _____ means: create an A called a with _____ as initializer. 这意味着确切的样子: A(3)创建一个用3初始化的临时A ,然后A a = _____意思是:创建a_____作为初始化程序的A

So you create a temporary, pass that to a as initializer, and then the temporary is destroyed. 因此,您创建了一个临时文件,将该临时文件传递给a作为初始化程序,然后销毁了该临时文件。 This type of initialization (with = ) is called copy-initialization (although don't confuse that with "copy", it's just a word). 这种类型的初始化(带有= )称为复制初始化 (尽管不要将其与“复制”混淆,这只是一个词)。

A constructor is selected to construct a which accepts an A . 选择一个构造函数来构造a接受A This must be either a copy or a move constructor. 它必须是副本或移动构造函数。 A has a move constructor and a copy constructor. A具有移动构造函数和复制构造函数。 The latter is implicitly-generated and defined as deleted too, because there is a user-declared move constructor. 后者是隐式生成的,并且也定义为Deleted,因为有一个用户声明的move构造函数。

Being defined as deleted doesn't affect overload resolution though; 但是,被定义为Delete不会影响重载解析; and the move-constructor is preferred to the copy-constructor in this case. 在这种情况下,move构造函数比copy构造函数更可取。

So your code attempts to call a delete d function, which is ill-formed, hence the error. 因此,您的代码尝试调用格式错误的delete d函数,从而导致错误。

Note that if the move-constructor were not deleted, then copy elision would apply. 请注意,如果未删除move-constructor,则将应用复制省略。 It kicks in in some circumstances where a variable is initialized from a temporary, or a local variable is returned by value. 在某些情况下,它会从临时变量初始化,或者按值返回局部变量。 The rule is that the compiler may use the same memory for both a and the temporary object, and omit the call to the copy/move constructor. 规则是编译器可以为a和临时对象使用相同的内存,并忽略对copy / move构造函数的调用。

Most/all compilers would actually do this in the circumstance. 在大多数情况下,大多数/所有编译器都会这样做。 So you can actually write auto a = A(3); 因此,您实际上可以auto a = A(3);auto a = A(3); and in practice not get any unnecessary moves. 并且在实践中不会采取任何不必要的措施。 If you write some code for your move-constructor that outputs something, you will hopefully find that nothing is output. 如果您为移动构造函数编写了一些输出内容的代码,则希望会发现什么都没有输出。

If you want to make absolutely sure there is no unnecessary copy, or construct an object that has no usable copy nor move constructor - stop writing code that specifies unnecessary copies! 如果要绝对确定没有不必要的副本,或者构造没有可用副本的对象,也不要移动构造函数-停止编写指定不必要副本的代码! A a(3); is sufficient. 足够了。

Why would you expect both code paths to be the same? 您为什么期望两个代码路径都相同?

You're obviously constructing an unnamed object in the second example, allocating a ( auto a ) and then copying from the temporary to a (which is a move because we're talking about a temporary object). 显然,在第二个示例中,您正在构造一个未命名的对象,分配aauto a ),然后将其从临时对象复制到a (这是一个步骤,因为我们正在谈论临时对象)。

It doesn't matter that compiler will generate the same code in both cases, because at compile time the necessary functions/constructors are needed to be defined. 两种情况下编译器都将生成相同的代码无关紧要,因为在编译时需要定义必要的函数/构造函数。 Think of it this way - optimization will occur after compilation/code-parsing, but in the end code willbe(should-be) the same in this case. 这样想吧-优化将在编译/代码解析之后进行,但最终在这种情况下,代码(应该)是相同的。

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

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