I have a basic C++ question which I really should know the answer to.
Say we have some class A with constructor A(int a). What is the difference between:
A test_obj(4);
and
A test_obj = A(4);
?
I generally use the latter syntax, but after looking up something unrelated in my trusty C++ primer I realized that they generally use the former. The difference between these two is often discussed in the context of built-in types (e.g. int a(6) vs int a = 6), and my understanding is that in this case they are equivalent.
However, in the case of user-defined classes, are the two approaches to defining an object equivalent? Or is the latter option first default constructing test_obj, and then using the copy constructor of A to assign the return value of A(4) to test_obj? If it's this second possibility, I imagine there could be some performance differences between the two approaches for large classes.
I'm sure this question is answered somewhere on the internet, even here, but I couldn't search for it effectively without finding questions asking the difference between the first option and using new, which is unrelated.
A test_obj = A(4); conceptually does indeed construct a temporary A object, then copy/move-construct test_obj from the temporary, and then destruct the temporary.
However this process is a candidate for copy elision which means the compiler is allowed to treat it as A test_obj(4); after verifying that the copy/move-constructor exists and is accessible.
From C++17 it will be mandatory for compilers to do this; prior to that it was optional but typically compilers did do it.
Performance-wise these are equivalent, even if you have a non-standard copy constructor, as mandated by copy elision. This is guaranteed since C++17 but permitted and widely present even in compilers conforming to earlier standards.
Try for yourself, with all optimizations turned off and the standard forced into C++11 (or C++03, change the command line in the top right):
https://godbolt.org/g/GAq7fi
Related
It would be nice to be able to easily text search in my codebase for places where is constructor of some object called. Here comes pattern bellow. Instead of classical:
Object val( a, b );
It would be nice to use everywhere:
auto val = Object( a, b );
That way I can use simple text search for "Object(" and get list of places where I am calling constructor of Object. It's also less syntacticaly ambiguous and therefore easier to make simple tools to automate some code transformations. It elegantly avoids "most vexing parse" issues too.
My only concern is about possible impact on performance. Is case 2) as fast a as case 1)? (If we can assume that Object has properly defined move constructor and move assignment operator and basic compiler optimizations are enabled.)
Pre C++17, it is possible, although unlikely, that you would get a performance penalty due to an extra copy or move. Even C++98 allowed implementations to remove such copies even if they would produce side-effects, and almost all compilers have implemented this optimization for a long time -- especially in optimized builds.
Post C++-17, copy elision is guaranteed. You aren't even required to have a copy or move constructor for this to work, so you shouldn't see any difference.
Some days ago, while reading Standard C++ news I've read the post about Defaulted functions in C++11, in that article is mentioned that the user-defined constructor is less efficient than the one generated by the compiler:
The user-defined default constructor is less efficient than the compiler implicitly defined default constructor.
Continuing the reading, there's an example where an user-defined constructor is marked as default, and then says:
the explicitly defaulted constructor is more efficient than a manually programmed default constructor.
I don't understand these assertions, so I was wondering:
Why a user-default constructor (or special member function) would be less efficient than the compiler implicitly defined one?
How is the efficiency improved by explicitly defaulting a constructor (or special member function)?
What guidelines I must follow to choose to default a constructor (or special member function) and how the efficiency affects this decision?
I think a better statement is that a user-defined default constructor MAY be less efficient than a compiler generated out.
For example, when it's generating a default constructor internally the compiler may be able to make assumptions and optimizations that it can't make for a user-defined contstructor (side-effects come to mind).
Also keep in mind that a user-defined default constructor could do totally different work that default-constructing all its members, resulting in it being less efficient (but also more correct). This doesn't seem to be the case in the link you provided however.
And we all know, that if it's written on internet then it is must be right... Wait, do we?
In the article where I found the first assertion of less efficient, the author tells the truth. Though you seem to misinterpret it -- in the example it refers to the hand-crafted ctor uses assignment. For no good reasons, and going against 2 decade old guidelines.
Next instance, same case. (As a practical note I shall add, that for any compiler claiming to have optimizations I expect the same assy output even for that form...)
I see no reason why the proper handwritten ctor would be different from the defaulted one in any ways, including efficiency. OTOH if they are identical why on earth write it? I'm all too happy that compiler makes it for me. And finally I can even control it in some ways I previously could not. Could use more of such functions. ;-)
Somewhat related to Why is copy constructor called instead of conversion constructor?
There are two syntaxes for initialization, direct- and copy-initialization:
A a(b);
A a = b;
I want to know the motivation for them having different defined behavior. For copy initialization, an extra copy is involved, and I can't think of any purpose for that copy. Since it's a copy from a temp, it can and probably will be optimized out, so the user can't rely on it happening - ergo the extra copy itself isn't reason enough for the different behavior. So... why?
Only a speculation, but I am afraid it will be hard to be more certain without Bjarne Stroustrup confirming how it really was:
It was designed this way because it was assumed such behaviour will be expected by the programmer, that he will expect the copy to be done when = sign is used, and not done with the direct initializer syntax.
I think the possible copy elision was only added in later versions of the standard, but I am not sure - this is something somebody may be able to tell certainly by checking the standard history.
Since it's a copy from a temp, it can and probably will be optimized out
The keyword here is probably. The standard allows, but does not require, a compiler to optimize the copy away. If some compilers allowed this code (optimized), but others rejected it (non-optimized), this would be very inconsistent.
So the standard prescribes a consistent way of handling this - everyone must check that the copy constructor is accessible, whether they then use it or not.
The idea is that all compilers should either accept the code or reject it. Otherwise it will be non-portable.
Another example, consider
A a;
B b;
A a1 = a;
A a2 = b;
It would be equally inconsistent to allow a2 but forbid a1 when As copy constructor is private.
We can also see from the Standard text that the two methods of initializing a class object were intended to be different (8.5/16):
If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3). If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The function selected is called with the initializer expression as its argument; if the function is a constructor, the call initializes a temporary of the cv-unqualified version of the destination type. The temporary is a prvalue. The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see 12.2, 12.8.
A difference is that the direct-initialization uses the constructors of the constructed class directly. With copy-initialization, other conversion functions are considered and these may produce a temporary that has to be copied.
Take the following example:
struct X
{
X(int);
X(const X&);
};
int foo(X x){/*Do stuff*/ return 1; }
X x(1);
foo(x);
In the compilers I tested, the argument to foo was always copied even with full optimization turned on. From this, we can gather that copies will not/must not be eliminated in all situations.
Now lets think from a language design perspective, imagine all the scenarios you would have to think about if you wanted to make rules for when a copy is needed and when it isn't. This would be very difficult. Also, even if you were able to come up with rules, they would be very complex and almost impossible for people to comprehend. However, at the same time, if you forced copies everywhere, that would be very inefficient. This is why the rules are the way they are, you make the rules comprehensible for people to understand while still not forcing copies to be made if they can be avoided.
I have to admit now, this answer is very similar to Suma's answer. The idea is that you can expect the behavior with the current rules, and anything else would be too hard for people to follow.
Initialization of built-in types like:
int i = 2;
is very natural syntax, in part due to historical reasons (remember your high school math). It is more natural than:
int i(2);
even if some mathematicians may argue this point. After all, there is nothing unnatural in calling a function (a constructor in this case) and passing it an argument.
For built-in types these two types of initialization are identical. There is no extra copy in the former case.
That is the reason for having both types of initialization and originally there was no specific intention to make them behave differently.
However, there are user-defined types and one of the stated goals of the language is to allow them to behave as built-in types as closely as possible.
Thus, copy construction (taking input from some conversion function, for example) is the natural implementation of the first syntax.
The fact that you may have extra copies and that they may be elided is an optimization for user-defined types. Both copy elision and explicit constructors came much later into the language. It is not surprising that standard allows optimizations after a certain period of use. Also, now you can eliminate explicit constructors from the overload resolution candidates.
With the new standard, there are new ways of doing things, and many are nicer than the old ways, but the old way is still fine. It's also clear that the new standard doesn't officially deprecate very much, for backward compatibility reasons. So the question that remains is:
What old ways of coding are definitely inferior to C++11 styles, and what can we now do instead?
In answering this, you may skip the obvious things like "use auto variables".
Final Class: C++11 provides the final specifier to prevent class derivation
C++11 lambdas substantially reduce the need for named function object (functor) classes.
Move Constructor: The magical ways in which std::auto_ptr works are no longer needed due to first-class support for rvalue references.
Safe bool: This was mentioned earlier. Explicit operators of C++11 obviate this very common C++03 idiom.
Shrink-to-fit: Many C++11 STL containers provide a shrink_to_fit() member function, which should eliminate the need swapping with a temporary.
Temporary Base Class: Some old C++ libraries use this rather complex idiom. With move semantics it's no longer needed.
Type Safe Enum Enumerations are very safe in C++11.
Prohibiting heap allocation: The = delete syntax is a much more direct way of saying that a particular functionality is explicitly denied. This is applicable to preventing heap allocation (i.e., =delete for member operator new), preventing copies, assignment, etc.
Templated typedef: Alias templates in C++11 reduce the need for simple templated typedefs. However, complex type generators still need meta functions.
Some numerical compile-time computations, such as Fibonacci can be easily replaced using generalized constant expressions
result_of: Uses of class template result_of should be replaced with decltype. I think result_of uses decltype when it is available.
In-class member initializers save typing for default initialization of non-static members with default values.
In new C++11 code NULL should be redefined as nullptr, but see STL's talk to learn why they decided against it.
Expression template fanatics are delighted to have the trailing return type function syntax in C++11. No more 30-line long return types!
I think I'll stop there!
At one point in time it was argued that one should return by const value instead of just by value:
const A foo();
^^^^^
This was mostly harmless in C++98/03, and may have even caught a few bugs that looked like:
foo() = a;
But returning by const is contraindicated in C++11 because it inhibits move semantics:
A a = foo(); // foo will copy into a instead of move into it
So just relax and code:
A foo(); // return by non-const value
As soon as you can abandon 0 and NULL in favor of nullptr, do so!
In non-generic code the use of 0 or NULL is not such a big deal. But as soon as you start passing around null pointer constants in generic code the situation quickly changes. When you pass 0 to a template<class T> func(T) T gets deduced as an int and not as a null pointer constant. And it can not be converted back to a null pointer constant after that. This cascades into a quagmire of problems that simply do not exist if the universe used only nullptr.
C++11 does not deprecate 0 and NULL as null pointer constants. But you should code as if it did.
Safe bool idiom → explicit operator bool().
Private copy constructors (boost::noncopyable) → X(const X&) = delete
Simulating final class with private destructor and virtual inheritance → class X final
One of the things that just make you avoid writing basic algorithms in C++11 is the availability of lambdas in combination with the algorithms provided by the standard library.
I'm using those now and it's incredible how often you just tell what you want to do by using count_if(), for_each() or other algorithms instead of having to write the damn loops again.
Once you're using a C++11 compiler with a complete C++11 standard library, you have no good excuse anymore to not use standard algorithms to build your's. Lambda just kill it.
Why?
In practice (after having used this way of writing algorithms myself) it feels far easier to read something that is built with straightforward words meaning what is done than with some loops that you have to uncrypt to know the meaning. That said, making lambda arguments automatically deduced would help a lot making the syntax more easily comparable to a raw loop.
Basically, reading algorithms made with standard algorithms are far easier as words hiding the implementation details of the loops.
I'm guessing only higher level algorithms have to be thought about now that we have lower level algorithms to build on.
You'll need to implement custom versions of swap less often. In C++03, an efficient non-throwing swap is often necessary to avoid costly and throwing copies, and since std::swap uses two copies, swap often has to be customized. In C++, std::swap uses move, and so the focus shifts on implementing efficient and non-throwing move constructors and move assignment operators. Since for these the default is often just fine, this will be much less work than in C++03.
Generally it's hard to predict which idioms will be used since they are created through experience. We can expect an "Effective C++11" maybe next year, and a "C++11 Coding Standards" only in three years because the necessary experience isn't there yet.
I do not know the name for it, but C++03 code often used the following construct as a replacement for missing move assignment:
std::map<Big, Bigger> createBigMap(); // returns by value
void example ()
{
std::map<Big, Bigger> map;
// ... some code using map
createBigMap().swap(map); // cheap swap
}
This avoided any copying due to copy elision combined with the swap above.
When I noticed that a compiler using the C++11 standard no longer faults the following code:
std::vector<std::vector<int>> a;
for supposedly containing operator>>, I began to dance. In the earlier versions one would have to do
std::vector<std::vector<int> > a;
To make matters worse, if you ever had to debug this, you know how horrendous are the error messages that come out of this.
I, however, do not know if this was "obvious" to you.
Return by value is no longer a problem. With move semantics and/or return value optimization (compiler dependent) coding functions are more natural with no overhead or cost (most of the time).
This is a (hopefully) really simple question - I have been told recently that using C++ style initialisation is better than traditional (and more common) assignment.
So this code:
std::SomeSTLContainer::const_iterator it = container.begin();
std::SomeSTLContainer::const_iterator itEnd = container.end();
would be 'slower' or less efficient than:
std::SomeSTLContainer::const_iterator it ( container.begin() );
std::SomeSTLContainer::const_iterator itEnd ( container.end() );
I understand the reason for this - the first example causes default construction and initialisation then subsequent assignment rather than specific construction and direct assignment in the second example. However, on modern processors / compilers, does it really make a difference?
I have been told recently that using C++ style initialisation is better than traditional (and more common) assignment.
This is simply wrong.
I understand the reason for this - the first example causes default construction and initialisation then subsequent assignment rather than specific construction and direct assignment in the second example. However, on modern processors / compilers, does it really make a difference?
No, it doesn't make a difference. The C++ standard explicitly allows the assignment in that case to be omitted so that the same code will be produced. In practice, all modern C++ compilers do this.
Additionally, Charles is right: this would never call the assignment operator but rather the copy constructor. But as I've said, even this doesn't happen.
Your reasoning is not quite correct. Using an '=' in the definition does not cause default construction and assignment. In the 'worst' case, it uses the copy constructor from a temporary generated from the right hand side of the '='.
If the type of the right hand side is (const/volatile aside) of the same type or a derived type of the object being initialized then the two forms of construction are equivalent.
No, typically. This is because iterators are coded to be very thin wrappers, and optimizers are quite aggressive when it comes to thin wrappers. E.g. the normal iterator method is just a simple pointer operation, and the function body is available from the header. This makes it trivially inlinable. In this case, an iterator copy is behind the scenes probably just a pointer copy, so the same holds.
This really depends on the case and the general rule of thumb should be applied: measure.
If there are a lots of instantiations of those iterators (maybe in nested and sort loops, those shorter constructors can easily make a difference).
Altough as you suggested, many compilers already can optimize those on their own.
To be really sure if your compiler does this there is just one way: measure
A a = A( arg1, arg2, ... );
This assignment can, as Rudolf stated, be replaced by a simple construction: it's a construction. And indeed, it would be compiled into the equivalent of the more succinct
A a( arg1, arg2, ...);
It's mostly a style issue, but I prefer not mixing the 'assigment-style' construction with 'initializer-style' construction. This way I induce consistency throughout my code. This boils down to: always use initializer style construction :).