7

Copy elision is a neat optimization technique and in some cases relying on copy elision can actually be faster than passing around references "by hand".

So, let's assume you have identified a critical code path where you rely on the fact that the copy elision is performed by your compiler for the code path for maximum performance.

But now you are relying on a compiler optimization.

Is there any (compiler specific, obviously) way to ensure that the copy elision is actually performed and have the compiler (or another tool) generate a warning/error if the copy elision cannot be performed?

(I'm thinking of something remotely similar to Visual C++'s __forceinline than will generate a warning if the function marked thus isn't inlined by the compiler.)

Martin Ba
  • 37,187
  • 33
  • 183
  • 337
  • Since this question was asked and answered, C++17 has been published and supported in GCC, Clang, and MS VC++. Would you care to update it with that in mind? – Phil Miller Apr 08 '19 at 19:59
  • @PhilMiller - not sure how the *question* changes significantly in this light. I have upvoted you answer though. Useful info. – Martin Ba Apr 09 '19 at 07:47

4 Answers4

4

No.

But you can write an equivalent, although completely unreadable, code:

BigObj f()
{
    BigObj x(g());
    x.someMethod();
    return x;
}

//...
BigObj z = f();
//...

is translated (with copy elision) to:

void f(BigObj* obj)
{
    new(obj) BigObj(g());
    obj->someMethod();
}

//...
char z[sizeof(BigObj)];
f((BigObj*)&z[0]);
//...
((BigObj*)&z[0])->~BigObj();

But seriously, just write your code in such a way that the compiler can elide the copy. I.e. return only one object without branching:

BigObj f()
{
    BigObj x, y;
    // use x and y
    if(condition)
        return x;
    else
        return y;
    // cannot be elided
}


BigObj f()
{
    if(condition)
    {
        BigObj x;
        return x;
    }
    else
    {
        BigObj y;
        return y;
    }
    // can be elided
}
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • 1
    @MSalters mentioned a neat technique to allow different objects to be returned and still get copy elision: If the condition is true, just `swap` both and always return the first. – Xeo May 26 '11 at 15:06
  • 2
    @Xeo: please note that `swap` was just a special case. In general, you can transform a funtion with multiple returns to a single return by adding a `T return_value` on top, changing every return statement into an assignment to `return_value`, and finally returning `return_value`. Often, this pattern can be optimized further, e.g. by initializing `return_value` with a sensible value. – MSalters May 27 '11 at 08:12
4

Not really, except putting an assert(false); in the copy constructor.

Otherwise use your favorite profiler to measure that the interesting parts of your app is fast enough.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • Hmm ... the idea with the assert(false) in the copy *operator* seems nice. For std containers and such stuff, maybe one can whip up a proxy/wrapper object that has an assert in its copy operator. – Martin Ba May 26 '11 at 15:20
  • The copy [assignment] operator doesn't affect pass-by-value though. – Mark B May 26 '11 at 16:14
  • @Mark: You are right. The assert has go into the copy *constructor* (as this is the one thing we want to make sure isn't called). – Martin Ba May 27 '11 at 07:36
  • Would you care to update or drop this answer in light of P0135 adopted in C++17? – Phil Miller Apr 08 '19 at 19:58
2

In C++1z (expected 2017), some cases will be required to guarantee copy elision:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

Per the communal cppreference.com compiler feature support wiki GCC 7+ and Clang 4+ ensure this.

The optimization side of this fortunately should not require enabling newer language support, since it's a pure optimization (following older language standard allowances).

Also allowing the copy constructor to be unavailable when the optimization applies probably will require the newer language standard to be enabled during compilation, or use of a loose or extended mode that doesn't demand strict conformance (e.g. potentially GCC's -fpermissive).

Phil Miller
  • 36,389
  • 13
  • 67
  • 90
1

Is there any (compiler specific, obviously) way to ensure that the copy elision is actually performed and have the compiler (or another tool) generate a warning/error if the copy elision cannot be performed?

gcc (trunk) (not yet released v14) has -Wnrvo

"Warn if the compiler does not elide the copy from a local variable to the return value of a function in a context where it is allowed by [class.copy.elision]. This elision is commonly known as the Named Return Value Optimization."

gcc (trunk) is available on https://godbolt.org/