4

My head hurts: I've read so many blogs about C++11x's move semantics that my brain's gone mushy, so please can someone give me a short-but-sweet guide on how to make the following code work efficiently? Given a class Foo, I want to be able to write functions that return Foo objects in different states (sometimes called source functions), and to do this as efficiently as possible.

class Foo {
    // Some methods and members
};

Foo getFirstFoo() {
    Foo foo;
    // Do some things to foo
    return foo;
} 

Foo getSecondFoo() {
    Foo foo;
    // Do some different things to foo
    return foo;
} 

int main() {
    Foo f = getFoo();
    // use f ...
    f = getSecondFoo();
    // use f ...
    return 0;
}

I don't want to modify Foo much, and the idea is to allow all sorts of Foo objects to be created through a variety of non-member source functions, so adding ever more constructors would be missing the point.

In C++03 my options would be to wrap the returned object in an auto_ptr (a big downside being that the recipient code needs to know to handle a smart pointer), or to cross my fingers and hope that some sort of optimization might take place (likely for the first line in main, less so for the second). C++11x seems to provide something better through move semantics, but how would I take advantage of these? So I need to change the way objects are returns in the source functions, or add some move constructor to Foo, or both?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
beldaz
  • 4,299
  • 3
  • 43
  • 63
  • 1
    Have a look at this: [Cpp-Next: Want speed pas by value](http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/) – mark Nov 23 '11 at 10:00

1 Answers1

6

This is already optimal1, provided that move constructors are generated2:

class Foo {
    public: 
        Foo(Foo&&) = default;
        Foo& operator=(Foo&&) = default;
};

Returned values are rvalue references by default.


1 Well.... provided that your class Foo benefits from move construction at all. Remember, move is an optimization of copy. Some copies cannot be improved! E.g, unsuited:

struct Foo  { int data; };
struct Foo2 { int data[5<<10]; };

well suited:

struct Foo3 { std::vector<std::string> data; };

See Move semantics - what it's all about? for a more general background on things like this.


2 Not all compilers do support that yet (even if they do implement rvalue references), so you might have to write the

  • move constructor
  • move assignment
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I reckon that's what I'm after. Thanks. I'm not too worried about the compiler support - GCC is fairly up to date in this regard, and the others will catch up be the time I finally complete my project... – beldaz Nov 23 '11 at 10:39
  • It is also worth nothing that the compiler-generated constructors and operators are disabled when you do certain things (like define a constructor of your own). Therefore, if you've done any of those things, you'll need to explicitly declare the otherwise normally-generated methods. You can use `= default` in those cases to get the default implementation, as indicated in the answer. – Michael Price Nov 23 '11 at 17:26