Question

I've been reading about how Copy ellision and return value optimization can improve speed by avoiding calls to an object copy constructor. I understand how the mechanisms work, but I wondered if this could not lead to programs that don't behave as one would expect.

In essence, my question is; what happens if we write the copy constructor to not create an object that is a copy of another object? In other words, what if

AClass original;
AClass copy ( original );
// copy == original -> false

Say, for example, we had a class like so:

// AClass.hpp

struct AClass
{
    static int copyCount;
    int copyNumber;

    AClass():copyNumber(0){}
    AClass( AClass const& original ):copyNumber(++copyCount){} // I think this is the signature for the copy constructor
};


// AClass.cpp

int AClass::count ( 0 );

This is obviously terrible behavior to put into a class, I'm not saying I'd do anything like this. The point stands, however; what if we relied on the side-effects of the copy? In this example, keeping track of how many copies we've made. I would expect that an optimization should not affect how the program runs. However, copy elision could cause the following code to fail:

// Main.cpp

AClass MakeAClass()
{
    return AClass();
}

int main()
{
    AClass copy ( MakeAClass() );

    if ( AClass::copyCount == 1 )
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

This could return 0 when I build in debug mode with no optimizations, but suddenly fail when I turn on optimizations and the return from MakeAClass is placed directly on copy, skipping the copy constructor.

Is there a check when the compiler attempts these optimizations to look for side-effects? Is it wrong to expect the code to perform a copy when you ask for a copy?

Was it helpful?

Solution

Yes. Copy elision can change the behavior of your code if your copy constructor (or your move constructor or your destructor) has side effects.

That's the whole point. If it could not change the behavior, there would be no reason to mention it in the standard. Optimizations which don't change behavior are already covered by the as-if rule. (1.9/1) That is:

The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.

Copy elision is explicitly mentioned in the standard precisely because it potentially violates this rule.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top