views:

123

answers:

2

T x(value) is usually the better choice because it will directly initialize x with value, whereas T x = value might create a temporary depending on the type of value. In the special case where value is of type T though, my guess is that the expression T x = value will always result in exactly one copy constructor call. Am I correct?

I've asked this question because I'm starting to think that the first syntax is too ugly and harder to understand, especially when value is the result of a function call. e.g:

  • const std::string path(attributes.data(pathAttrib));
  • const std::string path = attributes.data(pathAttrib);
+5  A: 

T x(value) is usually the better choice because it will directly initialize x with value, whereas T x = value might create a temporary depending on the type of value.

You're almost right, the better choice is the clearest syntax. Here's how the two differ:

The form of initialization (using parentheses or =) is generally insignificant, but does matter when the entity being initialized has a class type... [8.5/11]

struct A {
  A(int) {}
};
struct B {
  explicit B(int) {}
};

int main() {
  { A obj (42); } // succeeds
  { A obj = 42; } // succeeds

  { B obj (42); } // succeeds
  { B obj = 42; } // fails
}

An implicit conversion is required, so things like vector<int> v = 3; fail, but that looks wrong anyway, right? Any copy is likely elided. I can't remember finding this to be a bottleneck in anything I've written, and I stopped worrying about it long ago: just use the clearest syntax.


In the special case where value is of type T though, my guess is that the expression T x = value will always result in exactly one copy constructor call. Am I correct?

No, you're not guaranteed that the copy ctor will always be called, but it must be accessible. For example, in your specific case above with value being a function's return value, the standard explicitly allows those copies to be elided.

Roger Pate
But there is no copy and no semantic difference if `value` is of type `T` which is what the question asks. [8.5/14]
Charles Bailey
Nothing in /14 guarantees there is no copy, and whether the copy ctor is elided or not still applies. But yes, I did answer more generally than strictly required.
Roger Pate
I have to disagree, for direct-initialization and copy-initialization where the source and destination types are the same (modulo cv-qualifiers and derived class), only constructors are considered and the constructor chosen is used with the initializer expression as argument. There is no licence for the compiler to create a temporary in this case.
Charles Bailey
Not a temporary copy, a copy is always done in situations such as `T a; T b = a;`. But in the case asked about, when the value is returned by a function, eliding the copy ctor applies.
Roger Pate
I see what you're saying. We don't know whether the function returns by value or by reference, though. My understanding is that the question was about whether direct-initialization guarantees no extra invocations of the copy constructor over copy-initalization in the case where the source type is the same as the destination. It's my interpretation of the standard that both versions are equivalent. Evidently in this particular copy-initialization case it must be that the copy constructor is chosen to initialize the destination, whether the initializer is a temporary is an orthogonal issue.
Charles Bailey
+1  A: 

From the standard, copy-initialization for class types where the cv-unqualified type of the source type is the same as, or a derived class of the destination, has exactly the same behaviour as direct-initialization. The description of these two cases introduce a single paragraph describing the required behaviour which is that only constructors for the destination type are considered and the constructor chosen is used to initialize the destination with the initializer expression as argument.

No extra temporary is allowed in these cases.

Neither form of initialization prevent the optimizations described in 12.8 [class.copy] from occuring. Though a non-normative example, the example in 12.8/15 uses the copy-initialization form of initializer to demonstrate the elimination of two copies resulting from a function returning a local variable by value to an object initializer. This means that if value in your example is a temporary of type T then it - and the copy operation to x - may be eliminated.

Charles Bailey