Will any compiler actually ever elide these copies

2019-06-18 12:26发布

问题:

Given

struct Range{
    Range(double from, double to) : from(from), to(to) {}
    double from;
    double to;
    // if it matters to the compiler, we can add more fields here to make copying expensive
};

struct Box{
    Box(Range x, Range y) : x(x), y(y) {}
    Range x;
    Range y;
};

someone said that in Box box(Range(0.0,1.0),Range(0.0,2.0)), the compiler can avoid copying Range objects altogether by constructing them inside box to begin with.

Does any compiler actually do this?

My own attempts haven't succeeded.

回答1:

The compiler can - and normally does - elide the copies from the temporary to the argument. The compiler cannot elide the copy from the argument to members. While it may technically possible to elide these copies in some cases, the relevant permission isn't given. The section of the standard is 12.8 [class.copy] paragraph 31 which spells out 4 situations where a copy can be elided (the exact rules are a bit non-trivial):

  1. When returning a named, function local variable using it name.
  2. When using a named, function local variable in a throw expression.
  3. When copying a temporary object.
  4. When catching an exception by value.

Passing a named argument as parameter to the construction of a member variable is, clearly, none of these situations.

The essential background of the rules for copy elision is that in some contexts the declaration of functions suffice to determine when an object will be used. If it is clear upon construction time where the object can be constructed, it can be elided. The caller of a constructor cannot determine based only on the declaration of the constructor where the object will be used.



回答2:

That Someone is me. So let me clear my stand.

I never said that in Box box(Range(0.0,1.0),Range(0.0,2.0)), the compiler can avoid copying Range objects altogether by constructing them inside box to begin with. What I said was:

Yes it can, In particular this kind of copy elision context falls under the copy elision criterion specified in 12.8/p31.3 Copying and moving class objects [class.copy] of the standard:

(31.3) -- when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same type (ignoring cv-qualification), the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move.

The Yes it can, part goes for the temporary objects passed in the constructor (That can be elide per standard as mentioned above). I never said that the parameters can be elided all the way to the Box constructor's initializer list.

After all, that case doesn't qualify for any of the criteria where copy elision can be applied as per standard.

I also said that even if a certain context is qualified as a context where copy elision can be applied, the compiler is not obligated to follow. If you rely on that effects then your program is not considered portable.