3

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 ?

  • 3
    Assignment is not used here becuase, well, there are no assignments in the main function at all. – kraskevich Feb 12 '15 at 21:41
  • 1
    Note that `testing_var1` and `testing_var2` are dangling references (if you add destructor output you'll see that straight away) - there is no lifetime extension of temporary here – M.M Feb 12 '15 at 23:15
  • In 1st, I do understand, but still don't get why 2nd is dangling reference... `testing_var2` is constructed by move constructor, and deconstructed at the end of main, so it doesnt't look like to me as dangling reference... – Sebastian Kuczyński Feb 13 '15 at 00:44
  • 1
    You're right; `1` is a dangling reference but `2` is not. The rule is that an rvalue reference extends lifetime when bound to a *prvalue*, but not when bound to an *xvalue*. [Explained here](http://stackoverflow.com/a/3716360/1505939) – M.M Feb 13 '15 at 00:58

3 Answers3

3

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.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
0

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.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0

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.

Jamerson
  • 474
  • 3
  • 14