passing heavy objects C++0x
Asked Answered
G

5

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

Groin answered 18/6, 2011 at 16:16 Comment(2)
See also Move or Named return value optimizationPhrygia
@Tom'... well I like to specific :DGroin
O
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

Ostium answered 18/6, 2011 at 16:26 Comment(4)
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. :DGroin
@111111: You should watch the other videos in that serie to ,they're very informative.Ostium
that these videos are very imformative and the guy doing them is pretty funny 'if you remember auto_prt forget them'.Groin
@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: blogs.msdn.com/b/vcblog/archive/2009/02/03/… It's kinda hard to cut+paste and actually try examples yourself, if they're just pictures on a video screen.Tody
A
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.

Antecedency answered 18/6, 2011 at 16:24 Comment(3)
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.Groin
So if what you saying is right I shoudn't put && in the return type and the compiler will do the rest?Groin
@Groin Yes, you should remove the && in the return type. Otherwise you will return a dangling reference.Antecedency
C
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.

Callihan answered 19/6, 2011 at 0:18 Comment(0)
O
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

Ostium answered 18/6, 2011 at 16:26 Comment(4)
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. :DGroin
@111111: You should watch the other videos in that serie to ,they're very informative.Ostium
that these videos are very imformative and the guy doing them is pretty funny 'if you remember auto_prt forget them'.Groin
@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: blogs.msdn.com/b/vcblog/archive/2009/02/03/… It's kinda hard to cut+paste and actually try examples yourself, if they're just pictures on a video screen.Tody
A
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.

Anemia answered 18/6, 2011 at 16:26 Comment(5)
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 BTWGroin
@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.Tody
@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&&).Anemia
cool, I get you now. thanks. I wrongly thought that it would construct then init'.Groin
@111111: assignment isn't the same as initialization. And type var = value; syntax is initialization, not assignment.Tody
P
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.)

Peterkin answered 18/6, 2011 at 16:28 Comment(1)
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 feelGroin

© 2022 - 2024 — McMap. All rights reserved.