7

I have a function which produces a type of expensive object (containing vectors and a maps of a non fixed size) so I really want to avoid invoking copy c'tors.

Until now I have just returned a std::shared_ptr from the method and used that but I think it is ugly and requires typedeffing to be really usuable.

I am aware of two thing that may help me. Firstly copy elision and the second is the move semantic.

My problem is that I know how to use neither properly. My research has told me that copy elision is entirely done by compiler and is not apart of the st'd. I don't really want to have to solely rely on this.

So how do I ensure that move assigment is invoked and does having it in place going to prevent the compiler from doing to copy elision.

ResultSet &&generateResults()
{
    //ResultSet a(); :S
    ResultSet a;
    a.populat(...
    //blah blah blah
    return a;
}

//else where (where the && assignment operator is overloaded
ResultsSet b = generateResults();

In this case is this the most correct way to code this? and if not how could I improve it. I am happy to use C++0x only constructs.

BTW: My compiler is gcc 4.6

Alex Bitek
  • 6,529
  • 5
  • 47
  • 77
111111
  • 15,686
  • 6
  • 47
  • 62

5 Answers5

4

A good answer to your questions can be found in this blog post series by Dave Abrahams:

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

It covers interactions among rvalue references, move constructors and copy elision. It's a bit long but it is worth to read the whole thing :)

The short story is that copy elision has the precedence. If for some reason it does not (or cannot) happen, the compiler must first consider the move constructor and finally the copy constructor.

bluescarni
  • 3,937
  • 1
  • 22
  • 33
  • I have read that and the companion article. But I was still left with the above question. I should point I have only been C++ for a few months (from ansi C). I am sure you can appreciate there is a lot to learn I just want to do it right from the off rather than having to toss out my code I am writing now in a couple of years. – 111111 Jun 18 '11 at 16:27
  • So if what you saying is right I shoudn't put && in the return type and the compiler will do the rest? – 111111 Jun 18 '11 at 16:28
  • 3
    @111111 Yes, you should remove the && in the return type. Otherwise you will return a dangling reference. – bluescarni Jun 18 '11 at 16:30
4

In this case is this the most correct way to code this?

Actually, it is the "least correct" way: you are returning a reference to an automatic object. When the function returns, the client receives a reference to an object that no longer exists.

There is no difference between lvalue references and rvalue references in this respect. So just get rid of the rvalue reference and return the result by value. You will either get NRVO or move semantics.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
3

If you don't like reading ,here is a link to a video about rvalues and move-semantics: http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n

engf-010
  • 3,980
  • 1
  • 14
  • 25
  • I don't mind reading, just when EVERYTHING is new I feel that fail to take much in. I will definitely watch that video now. :D – 111111 Jun 18 '11 at 16:33
  • @111111: You should watch the other videos in that serie to ,they're very informative. – engf-010 Jun 18 '11 at 16:41
  • that these videos are very imformative and the guy doing them is pretty funny 'if you remember auto_prt forget them'. – 111111 Jun 18 '11 at 17:07
  • @111111: If you prefer to read the information (I know it's much easier for me to process), see this blog post by the same author: http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx It's kinda hard to cut+paste and actually try examples yourself, if they're just pictures on a video screen. – Ben Voigt Jun 18 '11 at 17:56
3

Your research is wrong. Copy elision is absolutely Standard. It is not mandated but officially allowed. In the example of your function, I would definitely expect it to be applied, as the transformation is relatively trivial.

And secondly, you should not return an rvalue reference- just return by value. The compiler isn't mandated to elide the copy- although it probably still will- but it must invoke move semantics.

Oh, and you need to overload the move constructor, not the move assignment operator, for that specific piece of code, although of course ideally you would do both.

ResultSet a();

Does not define any variable, but declares a function called a taking nothing and returning a ResultSet.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • sorry that was wrong in my example. I know that i just forgot in my actual question params are passed to it but they don't concern this question. 'Oh, and you need to overload the move constructor' you mean it should be ResultSet b(generateResults()); Thank you BTW – 111111 Jun 18 '11 at 16:31
  • @111111: The code in your question is *copy-initialization* (and uses a move constructor if available, copy constructor otherwise), neither uses the assignment operator. Your comment uses *direct-initialization*, when the types match it works exactly the same way. An example which uses the assignment operator: `ResultSet b; b = generateResults();` Note that the assignment is now completely separate from object construction. – Ben Voigt Jun 18 '11 at 16:51
  • @111111: No, what I mean is that the difference between `ResultSet b(generateResults());` and `ResultSet b = generateResults();` is absolutely nothing at all- they both call the move constructor, `ResultSet::ResultSet(ResultSet&&)`- not `ResultSet::operator=(ResultSet&&)`. – Puppy Jun 18 '11 at 16:57
  • cool, I get you now. thanks. I wrongly thought that it would construct then init'. – 111111 Jun 18 '11 at 17:06
  • @111111: *assignment* isn't the same as *initialization*. And `type var = value;` syntax is initialization, not assignment. – Ben Voigt Jun 18 '11 at 17:53
0

You can learn about move constructors, and I am sure someone will provide an example for you.

But another option you might consider is unique_ptr. For your application, it should work just as well as shared_ptr and it would be significantly more efficient. (You might still want those typedefs, however.)

Nemo
  • 70,042
  • 10
  • 116
  • 153
  • thats. I wasn't sure how I would safely return a unique_ptr is it just return uptr or return move(uptr); but really I would like to get RVO and C-Elison working as it produces the cleanest code I feel – 111111 Jun 18 '11 at 16:36