The C++ Standard Library by Nicolai M. Josuttis states:
There is a minor difference between
X x;
Y y(x) //explicit conversion
and
X x;
Y y = x; //implicit conversion
Following to say: "The former creates a new object of type Y by using an explicit conversion from type X, whereas the latter creates a new object of type Y by using an implicit conversion."
I'm a little confused about the concepts of explicit vs implicit conversion I guess. In both cases you're taking an X and pushing it into a Y per se - one uses a Y's constructor and one uses the assignment operator though.
What's the difference in how the conversion is treated in these two cases, what makes it explicit/implicit, and how does this tie into making a class constructor defined with the "explicit" key word, if at all?
one uses a Y's constructor and one uses the assignment operator though.
Nope. In the second case it's not an assignment, it's an initialization, the assignment operator (operator=) is never called; instead, a non-explicit one-parameter constructor (that accepts the type X as a parameter) is called.
The difference between initialization and assignment is important: in the first case, a new object is being created, and it starts its life with the value that it is being initialized with (hence why a constructor is called), while assignment happens when an object is assigned (~copied) to an object that already exists and already is in a definite state.
Anyway, the two forms of initialization that you wrote differ in the fact that in the first case you are explicitly calling a constructor, and thus any constructor is acceptable; in the second case, you're calling a constructor implicitly, since you're not using the "classical" constructor syntax, but the initialization syntax.
In this case, only one-parameter constructors not marked with explicit are acceptable. Such constructors are called by some people "converting" constructors, because they are involved in implicit conversions.
As specified in this other answer, any constructor not marked as explicit can take part in an implicit conversion for e.g. converting an object passed to a function to the type expected by such function. Actually, you may say that it's what happens in your second example: you want to initialize (=create with a value copied from elsewhere) y with x, but x first has to be converted to type Y, which is done with the implicit constructor.
This kind of implicit conversion is often desirable: think for example to a string class that has a converting (i.e. non-explicit) constructor from a const char *: any function that receives a string parameter can also be called with a "normal" C-string: because of the converting constructor the caller will use C-strings, the callee will receive its string object.
Still, in some cases one-parameters constructors may not be appropriate for conversion: usually this happens when their only parameter is not conceptually "converted" to the type of the object being created, but it is just a parameter for the construction; think for example about a file stream object: probably it will have a constructor that accepts the name of the file to open, but it makes no sense to say that such string is "converted" to a stream that works on that file.
You can also find some more complex scenarios where these implicit conversions can completely mess-up the behavior that the programmer expects from overload resolution; examples of this can be found in the answers below the one I linked above.
More simply, it can also happen that some constructors may be very heavyweight, so the class designer may want to make sure that they are invoked explicitly. In these cases, the constructor is marked as explicit, so it can be used only when called "explicitly as a constructor" and doesn't take part in implicit conversions.
one uses the assignment operator though
No, it does not. It calls the constructor directly.
The reason why one is explicit and one is implicit is because implicit conversions can happen when you don't want them to. Explicit ones cannot. The easiest example of this is bool.
Let's say that you invent some type which can be either true or false- like a pointer. Then let's further say that you decide that in order to make life easier for your users, you let it convert to bool implicitly. This is great- right up until the point where one of your users does something dumb.
int i = 0;
i = i >> MyUDT();
Oh wait- why does that even compile? You can't shift a MyUDT at all! It compiles because bool is an integral type. The compiler implicitly converted it to a bool, and then to something that can be shifted. The above code is blatantly dumb- we only want people to be able to convert to a bool, not a bool and anything else that a bool might want to do.
This is why explicit conversion operators were added to C++0x.
The first form is direct initialization. The second is copy initialization.
Copy initialization implicitly calls a converting constructor or conversion operator and then explicitly calls a copy constructor (the copy constructor call may be elided, but an accessibility check must still be performed).
Consider a third possibility, which is copy-initialization, but the conversion is explicit:
Y y = Y(x);
or
Y y = (Y)x;
The Implicit casting doesn't require any casting operator. This casting is normally used when converting data from smaller integral types to larger or derived types to the base type.
int iVal = 100;
double dVal = iVal;
The explicit converting constructor is preferred to the implicit conversion operator because in the latter case there is an additional call to the copy constructor.Implicit and Explicit converstions
Related
Why is this way of initialisating a std::string:
std::string s = "123";
considered a copy initialisation, when no copy whatsoever actually occurs?
In the above case, there is no ambiguity that the compiler will see that there is a std::string constructor that takes a char const *, and consequently what happens here is construction of a std::string object via implicit conversion of char const * to std::string. This is such a clear-cut scenario. It's simply calling a std::string(const char *) constructor once, plain and simple. So simple there is even nothing to talk about regarding optimisations such as copy elision and move.
Now, the problem is, I never had any confusion about object initialisation via implicit conversion (i.e. Class a = expression) until I started coming across literature declaring that initialisation by = is "copy initialisation". Even the main man, Bjarne Stroustrup himself, refers to this form of initialisation as "copy initialisation".
At this point, I feel that I may be misunderstanding something.
So, why is initialisation by = considered copy-initialisation when clearly this is not the case if implicit conversion is allowed?
The term copy-initialization is simply used for an initializing syntax of the form:
T object = other;
where one of the effects of this initialization is:
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution.
So for the expression:
std::string s = "123";
the implicit constructor that takes a const char * is used to construct the std::string.
So even though it has the term copy in it, copy-initialization does not mean there is an actual copy involved, it's only called that because the syntax makes it appear like a copy is happening.
The reason it is called copy initialization is because before C++11, that is what literally had to be done, per the rules of the language. When you have
T t = u;
if u is a T, then you call the copy constructor. So calling it copy initialization for that case makes sense
if u is not a T then [dcl.init]/15 bullet 7 came into play (from the C++03 draft) and that has
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 an rvalue. 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.
emphasis mine
which states that a temporary is created, and that temporary is used to initialize them object. Yes, it says this can be avoided in certain cases, but those section only allow the optimization, it is not mandated to happen.
So, again we are making a copy, so copy initialization makes sense.
With C++17 this is no longer the case and your guaranteed that no copy will exist, but were stuck with the name at this point.
Since I have doubts about this question (for C++03) I am posting it here.I just read about conversion constructors and it states that
"To be a converting constructor, constructor must have single
argument and be declared without keyword explicit."
Now my question is whether the copy constructor can be called a conversion constructor provided it is not explicitly declared ? Does it qualify to be one ?
I believe it cant be called a conversion constructor because it only accepts the same type parameter ths resulting in no conversion. For Instance
foo a;
foo b;
a = 100; //a Conversion constructor would be called (i.e) foo(int a){...}
a = b ; //Since both objects are same type and have been initialized the assignment operator will be called (if there is an overloaded version otherwise the default will be called)
Is my understanding correct ?
Quoting the Standard:
[class.conv.ctor]/3
A non-explicit copy-constructor (12.8) is a converting constructor. An implicitly-declared copy constructor is not an explicit constructor; it may be called for implicit type conversions.
So yes, a copy-ctor is a converting ctor.
Also note [conv]/1 which specifies and points out in a remark:
Note: a standard conversion sequence can be empty, i.e., it can consist of no conversions.
and in /3:
An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed
So the set of implicit conversions contain the empty conversions.
Yes, a copy constructor is what it is -- a copy constructor. Which isn't a conversion constructor that converts from one type to a different type.
I know the concept that we can call the Constructor both Explicitly and Implicitly, and i have tested both the scenarios(generally till now my all purposes got fulfilled by calling constructor Implicitly), but i was wondering that constructor get called implicitly whenever we create objects, so what is the main reason behind calling the constructor Explicitly. What advantage or disadvantage it provides when we call constructor Explicitly over the Implicit Call?
Example
class integer
{
int m ,n;
public:
integer (int x , int y);
};
integer :: integer (int x , int y )
{
m=x; n = y;
}
Now if i call like
integer int1 = integer( 0 , 100); // Explicit Call
integer int1(1,100); // implicit call
There are two different problems here, as your definition of explicit and implicit does not match the standard definition (on which most of the existing answers are based, being written before you added your example containing your own definition of explicit and implicit).
Ok so let's first consider your definition of explicit, which would be (I guess you call it explicit because you explicitly write the type name?):
integer int1 = integer(0, 100);
versus your definition of implicit which would be:
integer int1(1, 100);
In this case the first "explicit" call really doesn't have any advantage over the second "implicit" call. But there is still a difference. The first one actually creates a temporary using the two-argument constructor, which is then used to create int1 using the copy constructor. Although in practice the compiler will usually optimize away this additional copy, it still won't work if your copy constructor is private, whereas the second one only needs the two-argument constructor (you could even see this as disadvantage).
But now to the actual standard definitions of explicit and implicit. An explicit constructor call is any constructor call you, well, explicitly call. Practically speaking, whenever you use the parenthesis syntax () to create an object you explicitly call a constructor, otherwise it's an implicit constructor call (so to say, being done behind the scenes by the compiler):
integer int1; // implicit default constructor
integer int1(1, 100); // explicit two-arg constructor
integer int1 = integer(0, 100); // explicit two-arg constructor, implicit copy constructor
void func(integer); // function taking by-value
func(int1); // implicit copy constructor
So the only constructors that can be called implicitly are the default construtor and any one-argument constructors (including copy and move constructors). A special problem in this regard are one-argument constructors not being copy/move constructors:
struct integer
{
integer(int);
};
This allows the compiler to imlicitly call the the constructor to convert types, thus any int is implicitly convertible to integer:
void func(integer);
func(42); // implicit call to int-constructor
To disallow such behaviour you would have to mark the constructor explicit:
struct integer
{
explicit integer(int);
};
Which only allows it to be called explicitly (e.g. func(integer(42))) (but I guess you already knew this). This has the advantage that it doesn't introduce unnoticed/unwanted conversions behind the scenes, which can lead to all kinds of hard to find problems and ambiguities regarding overload resolution. It is therefore usual practice to mark any conversion constructors (one-argument non-copy/move constructors) explicit, and most probably also the reason why C++11 finally introduced explicit conversion operators.
So to sum up, according to your definition and example, there is really no advantage in using integer int1 = integer(1, 100); instead of integer int1(1, 100);, though it makes a (usually irrelevant) difference.
But according to the standard definitions, explicit constructor calls have plenty advantages over implicit ones, since the only way to actually construct an object explicitly is to use a, well, explicit constructor call, whereas implicit constructor calls are only done behind the scenes in certain situations and only work for zero- and one-argument constructors (as aschepler already pointed out). And explicitly marking conversion constructors as explicit has the advantage of disallowing unwanted implicit conversions behind the scenes.
Calling constructors explicitly allow you to construct object with arguments, rather than using the default constructor.
class Foo
{
public:
Foo() {}
Foo(int bar) : mBar(bar) {}
private:
int mBar;
}
Foo f; // Implicitly constructed with default constructor.
Foo f(7); // Explicitly constructed with argument for 'bar'
There are three ways a constructor can be called:
Implicitly, by declaring an instance of the type without initializing it
Also implicitly, by either initializing an instance with = or by causing an implicit conversion from the argument type to your class.
Explicitly calling the constructor, passing arguments.
Which of these you can use in a particular context depends on the constructors you're calling.
class Foo
{
Foo(); // 1
Foo(int a); // 2
explicit foo(const std::string& f); // 3
Foo(int c, int d); // 4
};
This constructor will be called implicitly when declaring Foo f;. Never attempt to call a constructor without arguments explicitly, as Foo f(); will declare a function!
This one can be called by writing Foo f = 42; or Foo f(42).
The explicit keyword forbids implicit conversion by writing Foo f = std::string("abc"); or function_taking_foo(function_returning_string());.
As there are multiple arguments, the explicit version is the only suitable.
I hate to say this, because it is so perverse, but there is an additional way to explicitly call the constructor.
class integer
{
int m ,n;
public:
integer (int x , int y);
};
integer :: integer (int x , int y )
{
m=x; n = y;
}
The constructor can be explicitly called on an already-constructed object.
integer i(1,100);
i.~integer();
i.integer::integer(2,200);
Here I've constructed (explicitly) an instance of integer. Then I've explicitly called its destructor. Then I've explicitly called the constructor again. I suppose you might use this idiom in testing. I am not aware of any place in the standard that forbids it. It works in Visual Studio 2010. I haven't tested a really wide range of compilers.
These calls are explicit for large values of 'explicit'.
If you make a function that takes a reference to a object of your class, and you pass it another type other than your object the constructor of your class will convert that type to an object of your class. Any one argument constructor is treated as a conversion constructor. If you declare that constructor explicit, then passing a different type other than your object to that function will not convert it and the compiler will return an error
Look at the following two ways to create a new object of class Y:
(1)
X x;
Y y(x);//explicit conversion
(2)
X x;
Y y = x;//implicit conversion
The first way uses explicit conversion and another uses implicit conversion.But,I don't very understand how they work.What is their difference?Could someone interpret for me?The more detailed,the better.Thanks a lot.
The first is called direct-initialization while the second is called copy-initialization. Assuming that Y has a constructor that takes a X (or reference to it), direct-initiazliation will call that constructor directly and regardless of whether the constructor is marked as implicit. copy-initialization semantically is equivalent to:
Y y( implicit_conversion<Y>(x) );
That is, the argument is converted by means of an implicit conversion to the destination type and then the copy constructor is called to initialize the variable. In real life, the compiler will remove the copy and convert in place of the destination variable, but the compiler must check that there is an implicit conversion from X to Y, and the copy constructor is accessible.
Actually, both are implicit conversions assuming that your class "Y" has a constructor like:
public:
Y(X &x)
A class constructor with a single argument will perform the conversion for you.
To avoid implicit construction, use one of the following (one may be better for you based on your situation):
Don't declare a constructor with a single argument
Use the explicit keyword on the constructor declaration
Use an intermediate class (in other words only allow 'Y' to be initialized by 'Z', a class that never be assigned directly to 'Y')
Use a static member function to explicitly 'make' an instance of 'Y' using an 'X' (since the member function is not associated with an instance of the class
Assume that the following code is legal code that compiles properly, that T is a type name, and that x is the name of a variable.
Syntax one:
T a(x);
Syntax two:
T a = x;
Do the exact semantics of these two expressions ever differ? If so, under what circumstances?
If these two expressions ever do have different semantics I'm also really curious about which part of the standard talks about this.
Also, if there is a special case when T is the name of a scalar type (aka, int, long, double, etc...), what are the differences when T is a scalar type vs. a non-scalar type?
Yes. If the type of x is not T, then the second example expands to T a = T(x). This requires that T(T const&) is public. The first example doesn't invoke the copy constructor.
After the accessibility has been checked, the copy can be eliminated (as Tony pointed out). However, it cannot be eliminated before checking accessibility.
The difference here is between implicit and explicit construction, and there can be difference.
Imagine having a type Array with the constructor Array(size_t length), and that somewhere else, you have a function count_elements(const Array& array). The purpose of these are easily understandable, and the code seems readable enough, until you realise it will allow you to call count_elements(2000). This is not only ugly code, but will also allocate an array 2000 elements long in memory for no reason.
In addition, you may have other types that are implicitly castable to an integer, allowing you to run count_elements() on those too, giving you completely useless results at a high cost to efficiency.
What you want to do here, is declare the Array(size_t length) an explicit constructor. This will disable the implicit conversions, and Array a = 2000 will no longer be legal syntax.
This was only one example. Once you realise what the explicit keyword does, it is easy to dream up others.
From 8.5.14 (emphasis mine):
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 destination type. 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 class.temporary, class.copy.
So, whether they're equivalent is left to the implementation.
8.5.11 is also relevant, but only in confirming that there can be a difference:
-11- The form of initialization (using parentheses or =) is generally insignificant, but does matter when the entity being initialized has a class type; see below. A parenthesized initializer can be a list of expressions only when the entity being initialized has a class type.
T a(x) is direct initialization and T a = x is copy initialization.
From the standard:
8.5.11 The form of initialization (using parentheses or =) is generally insignificant, but does matter when the entity being initialized has a class type; see below. A parenthesized initializer can be a list of expressions only when the entity being initialized has a class type.
8.5.12 The initialization that occurs in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and brace-enclosed initializer lists (8.5.1) is called copy-initialization and is equivalent to the form
T x = a;
The initialization that occurs in new expressions (5.3.4), static_cast expressions (5.2.9), functional notation type conversions (5.2.3), and base and member initializers (12.6.2) is called direct-initialization and is equivalent to the form
T x(a);
The difference is that copy initialization creates a temporary object which is then used to direct-initialize. The compiler is allowed to avoid creating the temporary object:
8.5.14 ... 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.
Copy initialization requires a non-explicit constructor and a copy constructor to be available.
In C++, when you write this:
class A {
public:
A() { ... }
};
The compiler actually generates this, depending on what your code uses:
class A {
public:
A() { ... }
~A() { ... }
A(const A& other) {...}
A& operator=(const A& other) { ... }
};
So now you can see the different semantics of the various constructors.
A a1; // default constructor
A a2(a1); // copy constructor
a2 = a1; // copy assignment operator
The copy constructors basically copy all the non-static data. They are only generated if the resulting code is legal and sane: if the compiler sees types inside the class that he doesn't know how to copy (per normal assignment rules), then the copy constructor won't get generated. This means that if the T type doesn't support constructors, or if one of the public fields of the class is const or a reference type, for instance, the generator won't create them - and the code won't build. Templates are expanded at build time, so if the resulting code isn't buildable, it'll fail. And sometimes it fails loudly and very cryptically.
If you define a constructor (or destructor) in a class, the generator won't generate a default one. This means you can override the default generated constructors. You can make them private (they're public by default), you can override them so they do nothing (useful for saving memory and avoiding side-effects), etc.