A few times, when refactoring code, I have forgotten to add the explicit keyword when adding a parameter to a previously-parameterless constructor, or removing parameters from a previously multi-parameter constructor. To prevent this, I have gotten in the habit of marking every constructor explicit, no matter no many arguments it has. (Except, of course, those constructors for which I actually want implicit conversion.)
Is there any downside to this? Performance? Compile time?
It doesn't have any downsides. It will be future safe, because in C++0x multi-parameter constructors participate in initializations using multi-element initializer lists and can forbidden to be used in the cases where only implicit conversions apply using explicit.
So if you find out a give multi-parameter constructor does not logically represent the value of your class, I think it's good to make it explicit (example: I would set a container constructor (size_t size, T defaultValue) be explicit, while the constructor of pair, (T first, U second) be set non-explicit).
I'm not sure, but I think it does have some unexpected consequences for the copy constructor to be explicit. Other than that, I think yo're OK.
There will be no runtime performance difference. The compile time difference is likely to be undetectable.
I think there is no harm in declaring all constructors with arguments explicit, except that it might look redundant for those with more than one argument.
If you declare a type with an explicit default constructor, you may have trouble using it with collection types.
Related
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.
Some of my colleagues prefer to explicitly initialize std::auto_ptr to 0 in constructor initialization list, but it will be initialized to 0 in it's constructor without any explicit initialization. So is there any reason to do it?
#include <memory>
class A
{
A() : SomePtr(0)
{
}
private:
std::auto_ptr<SomeType> SomePtr;
};
No, the default constructor of std::auto_ptr does exactly that, so doing it explicitly is not necessary. In any case, it's a matter of style and you should be consistent. For instance, would you explicitly call the default constructor of a member vector in the constructor initialization list?
As a side note, std::auto_ptr is deprecated in the upcoming standard
Psychology.
For built-in types, you probably already know they are uninitialized unless you do so explicitly. For classes, this is not the case.
A strive to consistency results in explicit initialization everywhere. This allows you to forget if A::SomePtr is a built-in or a class type. Pretty useless, imho, since the amount of built-in types is quite limited.
One reason maybe clarity, but that should be the only one. I myself prefer not to write unneccessary intialization, especially if that completely spares me from writing a default constructor for the surrounding class and just let the compiler do its job. Whereas it's merely a matter of style, I think too much over-paranoia does even harm the clarity of the code.
The explicit keyword is recommended for all most constructors which can be called with one argument, except for copy constructors.
For copy constructors, it has an use (to forbid implicit copying via function call, return, etc), but it's not what's usually wanted.
What about move constructors? Is there any reasonable use case to make them explicit? What's the good practice here?
An explicit move constructors can affect compatibility with e.g. Standard algorithms. For instance, std::swap<T> requires that T be MoveConstructible. In turn, MoveConstructible is specified in terms of an expression, namely T u = rv; (where rv is an rvalue of type T).
If there is neither a non-explicit copy constructor nor a non-explicit move constructor for a given type then T u = rv; is invalid and that type can't be used with std::swap. (In this particular instance however it is possible to specialize std::swap to provide the desired functionality, e.g. by using T u(rv);).
Put more simply, an explicit move or copy constructor defies expectations and can't be used as well with generic code.
Some other parts of the Standard library that put a MoveConstructible requirement:
the deleter of unique_ptr<T, D>
call wrappers, used in e.g. bind (all the decayed types that are passed are concerned)
thread, async, call_once (all specified in terms of call wrappers)
sort, stable_sort, nth_element, sort_heap
The explicit keyword is recommended for (single argument) converting constructors, to avoid surprising conversions in unexpected places.
Copy constructors and move constructors are hardly "surprising" in that sense. They happen largely where expected. If you don't want them, I would expect them to be marked =delete rather than made explicit.
You probably want an implicit move constructor for the majority of uses. They generally fall into the same categories as copy constructors. Explicit isn't recommended for all one-argument constructors, but it is recommended for most. Move constructors are not on that list.
The actual question is how explicit move constructor could possibly be used? It wouldn't be able to be invoked on rvalues, so compiler would have to always select a copy constructor, if available, or fail to compile.
Edit: here is the link to example: http://www.ideone.com/nm7KM
When returning by value from a function, an implicit move constructor can usually make the process more efficient.
Could someone please explain what is meant by the following?
You must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.
What are they referring to as "badly"?
From the expansion of that link:
"The reason for this is that if you
have no other constructors and do not
define a default constructor, the
compiler will generate one for you.
This compiler generated constructor
may not initialize your object
sensibly."
Might refer to how new T and new T() differ when there is no ctor provided.
It's good to be sure that the object is created in a known state. Primitive variables won't be set to zero by default, so you could end up with subtle bugs that don't always show up. By initializing the member variables to sensible variables, everything is much more predictable.
The only problem with the default constructor is that it initializes only what the compiler thinks must be initialized, and not what you may think needs to be initialized. Basically, that means that it will invoke initializers for objects with default initializers. It won't set pointers or simple types like int to sane values, etc. If that is sufficient, then the default constructor is not 'bad'. When it is insufficient, it is a bug (in your code) that you did not define the necessary default constructor with the correct initialization.
Take the Google style guide with a grain of salt -- or maybe a truckload of salt.
It is true that the compiler-generated default constructor won't necessarily initialize members that are of built-in types in a meaningful fashion. If you want that done, then yes, its failure to do that is bad. OTOH, if you don't want that done, then its doing it could be somewhat bad (wasteful) as well.
Bottom line: there are times to write your own default ctor, but they tend toward the exception, not the rule. Although there are simple rules of thumb to cover a lot of cases in C++ and will prevent a lot of problems, this really isn't one of them -- here you pretty much do need to know what the compiler-generated ctor will do, and what you want different if you're going to write your own.
In Debug build most compilers fill uninitialized space with some magic values, so that debugging is reliable. And providing custom constructor prevents certain POD optimizations.
In fact, it's a guideline just to make sure people does explicitely make the statement of what is an invalid or default state of any object.
That way, no surprise when reading the code, compared to the actual execution.
However, think that it's a company guideline, that is used to make sure everyone does follow the same rules, that's not a you-must-follow-it-because-google-does-it.
In fact, if you manage to make all your member objects being in valid state when default constructed, or force you to set a constructor, then there is no good reason for such a guideline.
If you have any primitive types as member variables (eg. int, float), then the default ctor will not initialize them. member variables that are a class type will have their default ctor's invoked.
Prefer member initializer lists, so your user supplied ctor may be empty:
class Foo {
int bar;
float baz;
Foo(): bar(0), baz(0.0f) { /* empty ctor body */ }
};
It won't set integers to 0 or pointers to null. It will run default constructors on object of types with constructors.
Some people would call it 'not sensible'.
It just seems a too simplified version of the rules of 3, you should either define yourself or leave the compiler version of
the copy constructor
the assignment operator
the destructor
(Note that by defining yourself a copy constructor, the compiler won't define a default constructor).
The default constructor built by the compiler does 'nothing', it will not even zero the memory occupied by the object