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 start开发者_开发技巧ing 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);
T x(value)
is usually the better choice because it will directly initialize x with value, whereasT 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.
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.
精彩评论