views:

114

answers:

5

I have a function that looks like this:

// Fetch 1 MB of data
void GetData(std::vector<char> & outData);

The 1MB is exaggerated, but I just want to make the point that it's preferable to avoid unnecessary copies.

If I add this overload:

std::vector<char> GetData()
{
    std::vector<char> result;
    GetData(result);
    return result;
}

Then how likely is it that RVO will kick in?

+7  A: 

With most reasonably recent compilers (e.g., VS 2005 or newer, gcc 3.4 or newer), it's essentially certain. I only say "most" because I haven't tested every compiler in existence. Every new compiler I've looked at in probably the last 5 years or so has included it.

Jerry Coffin
Nitpick: VS 2005 also implements NRVO (http://msdn.microsoft.com/en-us/library/ms364057.aspx).
In silico
@In silico: fixed. Thanks -- I couldn't remember for sure exactly which iteration added it.
Jerry Coffin
Isn't there a surprise with VS that it won't perform NRVO in debug builds though ?
Matthieu M.
@Matthieu: I don't find it particularly surprising when an optimization isn't performed when you specifically ask to disable optimizations, but maybe that's just me.
Jerry Coffin
@Jerry: well, it might or might not be surprising, but that can be a huge performance hit (like using the STL debugging features) making the debug build unusable. If I remember correctly gcc performs the URVO even in debug but I am unsure about NRVO.
Matthieu M.
@Matthieu: Yes, it *definitely* has a major performance hit. Then again, MS is defaulting to leaving iterator checking on, even in release builds, and that probably has an even bigger effect on even more code. Personally, I don't mind a performance hit in debug mode, but (especially a big one) in release mode is a whole different story...
Jerry Coffin
+2  A: 

I don't think there's any standard answer to this: it depends on your compiler and what it's capable of.

If you're thinking of implementing this for convenience why not just try in on your compiler(s) and either look at the assembly or profile it and see what happens? Empirical evidence about what your compiler actually does is probably better than guessing what some compilers may or may not do.

Mark B
+3  A: 

RVO will most likely kick in, since it is a pretty simple optimization, which has been available for quite a while. However, in order to give this piece of code real practical value in even moderately high-performance code you'd need NRVO. NRVO is harder to come across, since it is relatively new. Yet it is available. MS compiler, for one example, implements it since VS2005.

AndreyT
A: 

Then how likely is it that RVO will kick in?

It is a software developer's job to think, not compiler's.

Compilers are generally optimized to make the good code work well - not the bad one.

Personally, I use the first form. Normally with a pointer instead of reference - to highlight the fact that the parameter is the output one, not input.

Dummy00001
Bad practice, since RVO will definitely kick in on any compiler you'd use today. NRVO is quite available too. Focus on clean code, not "fast" code. It's much simpler to do `auto x = get_something()` than `type x; get_something(x);`. If your profiler says its a problem, this question is a non-issue since you have to do it. (Note: "have" to. Not "could do and guessing I should.")
GMan
I do not mind typing - I'm a touch typist. And unfortunately `auto x = get_something();` causes people way often to forget that the function *might* be doing something expensive. And if the class/function later moved into a library then it often forgotten to be changed. `type x; get_something(` is guaranteed to work well regardless. And in debug builds too.
Dummy00001
@Dummy: Modern compilers do optimization at link-time as well. And in C++0x, the next standard, you'd only be slowing your program down by not returning by value (move-semantics). Clean code always wins, because clean code is easy to make fast.
GMan
@GMan: Compilers/linkers can do little about shared libraries - or 3rd party static libraries for which you have only headers. Neither unreleased C++0x's move c'tor (similar to .swap()) would magically make the already optimal code (no .swap()/etc at all) faster. (Ideally object code would be equivalent.) Subjective: I prefer the code which is clear about what/how it does. I planted the coding style in few companies before and it was picked precisely because of that: improved readability and fewer performance landmines.
Dummy00001
@GMan: Do not get me wrong. I dream about a language where I wouldn't need to think about all the nitty gritty implementation details. But C++ in its current incarnation (C++98) is not it.
Dummy00001
Shouldn't (N)RVO work no matter where the function originates? It doesn't depend on inlining or any other knowledge at the call site. Also I believe MSVC performs RVO even in debug mode, although NRVO still required turning on optimizations.
Dennis Zickefoose
A: 

Also, note that when you say:

std::vector<char> GetData() 
{ 
//   :
    return result; 
}

vector<char> x = GetData();

In the callee, result is copied to a "return value", and then in the caller, the "return value" is copied into x. NRVO can get rid of one of those copies, but not both. The compiler is obliged to call the copy ctor at least once, because it has to assume the copy ctor has side-effects which must be done.

James Curran
I'm not sure that's true if it can actually see the definition of the copy ctor (and everything it may call, recursively). But I agree with you that in practice, with separate compilation units, you're right.
Drew Hall
This is not true. There is even an example provided in the standard that illustrates this exact situation.
Dennis Zickefoose