0

Why does the standard allow my compiler to apply copy elision even when it involves visible side effects, thus breaks the as-if rule?

It is somehow plausible'ish for me when one has guaranteed copy elision, because the actual functionality for copy/move (which would invoke visible changes in the program behaviour) does not necessarily have to exist, but why/how was this before C++17?

Is it because a compiler can not generally detect side effects (I don't know whether this is possible)?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
nnolte
  • 1,628
  • 11
  • 25

2 Answers2

6

The cases that allow for this optimization involve copies of temporaries. Conceptually, these should have no visible effect but the language allows class writers to put whatever they want in a copy constructor.

As such, copy constructors might sometimes actually have visible side effects. Strictly speaking, the as-if rule may not be applicable.

It was deemed that this optimization was useful enough and the harm minimal enough to be worth including in the language. Consider that this optimization predates move semantics where return values would always be copied.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • How do you define "temporaries"? – juanchopanza Jul 11 '18 at 21:37
  • 1
    To make it more clear: A copy constructor should only copy things and as such a good copy constructor shouldn't have any side effects. Apart from theoretical code, it is highly unlikely that a copy constructor with side effects that break with copy elision exist. – Rakete1111 Jul 11 '18 at 21:39
  • 1
    Or the compiler cannot be expected to be able to actually *prove* there are no side-effects. Or the side-effects there are are of *no consequence*. – Deduplicator Jul 11 '18 at 21:39
  • 1
    @juanchopanza temporaries are [prvalues](https://en.cppreference.com/w/cpp/language/value_category#prvalue) – Tyker Jul 11 '18 at 21:39
  • @juanchopanza I'm using the term loosely. I haven't looked at all the cases to see if they share a common value category. I suspect they are all at least some form of rvalue. – François Andrieux Jul 11 '18 at 21:40
  • So it is really that the compiler cannot generally check for visible side effects? Or would this just be too much effort? – nnolte Jul 11 '18 at 21:40
  • @Tyker I don't think that would cover NRVO. – juanchopanza Jul 11 '18 at 21:42
  • 1
    @kawillzocken I would be surprised if a compiler could detect all possible side effects. It would need to be pessimist and required to prove the absence of side effects. But this optimization was so important at the time, I can see why they would opt to add an exception to ensure that it was always available as an option for the compiler. Without move semantics, it was very challenging to use the return value to *cheaply* pass large objects. Containers would need some shared state system, shared by copy, to avoid copying their content on being returned. – François Andrieux Jul 11 '18 at 21:44
  • @kawillzocken No, it is that the compiler doesn't *have* to check at all because the language spec says it doesn't, and programmers know that and write code accordingly. – juanchopanza Jul 11 '18 at 21:48
2

Proving things is hard, even if they are obviously true (whether they are true or not). Enabling the compiler to prove things in acceptable time is even harder. And then some side-effects might not actually matter, but how would you inform the compiler?

While copy-elision should not violate the as-if-rule (at least if the compiler knew which side-effeects to ignore in its analysis), the programmer has the freedom to write his types so it does anyway.

Finally, failure to prove that applying copy-elision does not violate the as-if-rule in a specific case might be very costly, as creating a copy of an object might be arbitrarily involved, needing time and space.

Thus, copy-elision was made an exception to the as-if-rule, being allowed regardless.

Now regarding guaranteed copy-elision, one has to concede that the rules are not necessarily completely obvious. Thus, it's a good thing that relying on it is only (?) necessary for performance, not correctness, at least where performance-requirements aren't too stringent..

Deduplicator
  • 44,692
  • 7
  • 66
  • 118