简体   繁体   中英

Difference between auto&& and auto

So, I've made such a class, and launched main:

class my_class{
public:
    my_class(): status("constructor"){
        cout << "constructor" << endl;
    }
    my_class(my_class&& obj): status("move constructor"){
        cout << "move constructor" << endl;
    }
    my_class(const my_class& obj): status("copy constructor"){
        cout << "copy constructor" << endl;
    }
    my_class& operator=(my_class&& obj){
        cout << "move assignment" << endl;
        return *this;
    }
    my_class& operator=(const my_class& obj){
        cout << "copy assignment" << endl;
        return *this;
    }
    ~my_class(){
        cout << "destructor; " << "object made by: " << status << endl;
    }
    string status;
};

my_class&& fun1(my_class&& temp){
    cout << "inside fun1" << endl;
    return move(temp);
}

my_class fun2(my_class&& temp){
    cout << "inside fun2" << endl;
    return move(temp);
}

int main(){
    auto&& testing_var1 = fun1(my_class{});
    auto&& testing_var2 = fun2(my_class{});
    auto testing_var3 = fun1(my_class{});
    auto testing_var4 = fun2(my_class{});
    return 0;
}

And what I've got really suprised me:

constructor
inside fun1
constructor
inside fun2
move constructor
constructor
inside fun1
move constructor
constructor
inside fun2
move constructor

Why when the "testing_var3" is returned by fun1, the move constructor is used? Why there is such a difference, when the deduction of type is made by auto not auto&&?

I thought that move assignment would be used, but move constructor in fun1 is for me nonsense...

And why the move constructor is used in fun2? Shouldn't it be move assignment?

/EDIT:

I've added some extra code to constructors and destructors. Now I get:

constructor
inside fun1
destructor; object made by: constructor
constructor
inside fun2
move constructor
destructor; object made by: constructor
constructor
inside fun1
move constructor
destructor; object made by: constructor
constructor
inside fun2
move constructor
destructor; object made by: constructor
destructor; object made by: move constructor
destructor; object made by: move constructor
destructor; object made by: move constructor

And my next question is: Why the first variable is dangling reference and other don't? Why second variable isn't such a reference, as suggested @MattMcNabb ?

Why when the "testing_var3" is returned by fun1, the move constructor is used?

testing_var3 is deduced as type my_class , therefore a constructor must be called to create a new my_class object. Since the right hand side is a temporary, the move constructor is chosen.

Why there is such a difference, when the deduction of type is made by auto not auto&&?

If you use auto&& then you always declare a reference, and a constructor is not called when a reference to class is bound to an expression of the same class type, because no new object is created. auto never declares a reference.

I thought that move assignment would be used, but move constructor in fun1 is for me nonsense...

And why the move constructor is used in fun2? Shouldn't it be move assignment?

There is no assignment occurring; just copy-initialization . In

T x = e;
T x = braced-init-list;

assignment operators are not called, despite the appearance of the = token. It's initialization, not assignment. Assignment requires an already-constructed object to assign to.

testing_var3 is constructed by move ctor and for the last the return value is constructed by a move ctor...

There is no assignment in fun2 only a returned value that need to be constructed/initialized.

I would recommend you read Scott Meyers' blog on "Universal References". auto&& can bind to an lvalue or an rvalue. In most situations, you won't need to use auto&&, unless you really know what you are doing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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