0

Try running this test program :

#include <iostream> class A { public: A() { std::cout << "empty constructor" << std::endl; } A(const A &a) { std::cout << "copy constructor" << std::endl; } A(A &&a) { std::cout << "move constructor" << std::endl; } ~A() { std::cout << "destructor" << std::endl; } A &operator=(const A &o) { std::cout << "copy assignment" << std::endl; return *this; } A &operator=(A &&o) { std::cout << "move assignment" << std::endl; return *this; } }; A outside; template <typename U> void bar(U &&a) { outside = std::forward<U>(a); } void foo(A &&a) { bar(a); } int main(int argc, char *argv[]) { foo(A()); return 0; } 

On my compiler, I think GCC 4.4.1, the output is:

empty constructor empty constructor copy assignment // what?? destructor destructor 

In my opinion the third line is strange. Why is outside copying a in bar instead of moving it? In other words,hy does foo use the bar(A &a) instantiation of bar instead of bar(A &&a)?

I should mention that this problem is easily fixable by changing foo to

template <typename U> void foo(U &&a) { bar(std::forward<U>(a)); } 

whereupon the move assignment operator is used instead.

In my code I have a lot of delegation methods and I'd hate to have to stick them all in a .h file and make templates for them. Is there another way of telling the compiler or making it understand that a is used as an rvalue in foo?

EDIT: A few people pointed out this change:

void foo(U &&a) { bar(std::move(a)); } 

I was too slow to indicate that I want foo to be able to accept both:

int main(int argc, char *argv[]) { foo(A()); return 0; } 

and

int main(int argc, char *argv[]) { A a; foo(a); return 0; } 

The suggested code will incorrectly steal, in the second case, a's resources in main where it should be used as a reference.

18
  • Because a in foo is an lvalue. You need bar(std::move(a));. I'm looking for a good duplicate. Commented Aug 24, 2015 at 22:47
  • I've edited the question to explain the problem more clearly. Thanks! Commented Aug 24, 2015 at 22:50
  • 1
    @bombax: There is really no other way. If you want to have a method that forwards then you need to either duplicate that method or template it. Commented Aug 24, 2015 at 23:00
  • 1
    In case it is still unclear: even if you wrote foo( (A&&)a ) (which is what your version of g++ is doing), then foo does not have the information about whether it was called with a temporary object or not; you have to either copy (bar(a)) or steal resources (bar(std::move(a))). The proper way to steal only from rvalues (without using a template) is to have a pair of overloads void foo(A& a) { bar(a); } void foo(A&& a) { bar(std::move(a)); } Commented Aug 24, 2015 at 23:28
  • 1
    An alternative to the overload pair is template<typename T> void foo(T &&a) { bar(std::forward(a)); } because forwarding references can deduce reference types; but I guess you didn't do this because you could have just called bar in the first place :) Commented Aug 24, 2015 at 23:31

1 Answer 1

2

Inside your foo function it should be: bar(std::move(a)) because the parameter a is at that point an lvalue.

Sign up to request clarification or add additional context in comments.

1 Comment

I've edited the question to illustrate what I wanted more clearly, thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.