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
Related
I am learning C++ using the resources listed here. In particular, I came to know that copy initialization is used when passing arguments to function parameters(by value) etc.
For example, from decl.init.general#14:
The initialization that occurs in the = form of a brace-or-equal-initializer or condition ([stmt.select]), as well as in argument passing, function return, throwing an exception ([except.throw]), handling an exception ([except.handle]), and aggregate member initialization ([dcl.init.aggr]), is called copy-initialization.
(emphasis mine)
My question is that is there is reason for using copy initialization instead of direct initialization when passing argument to function parameters(by value)?
To make the question more concise, lets look at a contrived example:
struct C
{
explicit C(int)
{
}
};
void func(C param)
{
}
int main()
{
C s1(2); //#1: this works, direct-initialization and so explicit ctor can be used
C s2 = 2; //#2: won't work, copy-initialization and so explict ctor cannot be used here
func(2); //#3: won't work, copy-initialization of parameter param and so explict ctor cannot be used here
return 0;
}
As we can see in the above example, the function call func(2) won't work because here the parameter param is copy initialized instead of direct initialized and so the explicit constructor C::C(int) cannot be used.
Summary
My question is why does the C++ standard(committee) choose to copy initialize the parameter param instead of direct initializing the parameter using the passed argument 2. I mean if param was direct initialized then the call func(2) would've succeeded.
Maybe there is a reason, like advantages of using copy initializing the parameter instead of direct initializing it or maybe there are disadvantages of using direct initializing the parameter instead of copy initializing it.
It is precisely so that this does not work.
The whole point of the distinction between copy-initialization and direct-initialization is to prevent implicit conversions in cases of copy-initialization. By using explicit in your constructor, you are declaring that you do not want integers to be converted to C unless the user spells it out directly.
When you attempt to call func(2), the type C is not explicitly visible anywhere near the call site. Therefore, it should be copy-initialization and if C's conversion constructor from int is explicit, the call should be disallowed.
could someone please explain the syntax of the following snippet from a c++ class template?
public:
explicit Foo(size_t ratio = 500)
:list(Bar<I>())
,vec(Bar<iterator>())
,n(0), r(ratio){}
I have decent experience with programming and understand most concepts but the syntax behind this is just so foreign to me, i can't understand it. I is the generic type. Specifically, I'm not sure what the explicit is doing here, in addition to what is going on when one would execute some code such as Foo<int> myfoo;.
thanks!
The explicit keyword makes sure that your constructor is not picked as part as a user-defined conversion sequence to perform implicit conversions when copy-initialized with a value of type size_t.
Without the explicit keyword, for instance, all of the following would be valid:
Foo<int> bar(Foo<int> f)
{
return 0; // OK
}
Foo<int> f = 1729; // OK
bar(42); // OK
Declaring your constructor as explicit prevents the initializations above from compiling.
What follows the constructor's signature is an initialization list, and it is used to construct the base class subobjects and data member subobjects of your class before the body of your constructor is entered.
When you do not use an initialization list, the data members of your class are default-constructed. This, however, may not be an option if your class has const data members, or data members of reference type, or data members of a class type which do not have a default constructor.
This is a constructor for the class Foo, but I'm sure you already knew that.
explicit says that this constructor must receive an argument of size_t. That is, one cannot pass in anything that would be implicitly casted to a type size_t (ex: int).
The rest of the things are part of the constructor's initializer list, which means the constructor initializes the data member list with Bar<I>(), etc.
This is the definition of a constructor for Foo. The constructor is explicit, which means that it won't be involved in implicit conversions. As an example consider:
void bar(Foo);
bar(10); // Error - would require an implicit conversion
Marking a constructor as explicit prevents such conversions.
Everything after the : is a member initialization list. It lists members of Foo by their names and the parentheses contain the expressions with which to initialize them. For example, list will be initialized with the temporary object created by Bar<I>(), n is initialized with 0, etc.
I'm reading a tutorial for C++ but it didn't actually give me a difference (besides syntax) between the two. Here is a quote from the tutorial.
You can also assign values to your variables upon declaration. When we
assign values to a variable using the assignment operator (equals
sign), it’s called an explicit assignment:
int nValue = 5; // explicit assignment
You can also assign values to variables using an implicit assignment:
int nValue(5); // implicit assignment
Even though implicit assignments look a lot like function calls, the
compiler keeps track of which names are variables and which are
functions so that they can be resolved properly.
Is there a difference? Is one more preferred over the other?
The first is preferred with primitive types like int; the second with types that have a constructor, because it makes the constructor call explicit.
E.g., if you've defined a class Foo that can be constructed from a single int, then
Foo x(5);
is preferred over
Foo x = 5;
(You need the former syntax anyway when more than one argument is passed, unless you use Foo x = Foo(5, "hello"); which is plain ugly and looks like operator= is being called.)
For primitive types both are equivalent, it is for user defined class types that there is a difference. In both cases the code that gets executed will be the same (after basic optimizations are performed), but the requirements on the types differ if the element from which we are initializing is not of the type that we are constructing.
The copy-initialization (T t = u;) is equivalent to copy construction from a temporary of type T that has been implicitly converted from u to t. On the other hand direct-initialization is equivalent to a direct call to the appropriate constructor.
While in most circumstances there will be no difference, if the constructor that takes the u is declared explicit or if the copy-constructor is inaccessible, then copy-initialization will fail:
struct A {
explicit A( int ) {}
};
struct B {
B( int ) {}
private:
B( B const & );
};
int main() {
A a(1); // ok
B b(1); // ok
// A a2 = 1; // error: cannot convert from int to A
// B b2 = 1; // error: B( B const & ) is not accessible
}
For some historical background, initially primitive types had to be initialized with copy-initialization. When *initializer-list*s were added to the language to initialize member attributes from a class, it was decided that primitive types should be initialized with the same syntax that classes to keep the syntax in the initializer list uniform and simple. At the same time allowing the initialization of classes by means of copy-initialization makes user defined types closer to primitive types. The differences in the two initialization formats comes naturally: int a = 5.0; is processed as a conversion from 5.0 to int, and then initialization of a from the int. The same goes with user defined types: T u = v; is processed as conversion from v to T, and then copy construction of u from that converted value.
when you are declaring a variable and initializing it, they are functionally the same in that context. I usually refer to the two as:
int nValue = 5; // assignment syntax
and
int nValue(5); // construction syntax
For basic types, I prefer assignment over construction since it is more natural, especially for those who have programmed in other languages.
For class types, I prefer construction syntax since it obviates the existence of a constructor function.
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
When constructor is explicit, it isn't used for implicit conversions. In the given snippet, constructor is marked as explicit. Then why in case foo obj1(10.25); it is working and in foo obj2=10.25; it isn't working ?
#include <iostream>
class foo
{
int x;
public:
explicit foo( int x ):x(x)
{}
};
int main()
{
foo obj(10.25); // Not an error. Why ?
foo obj2 = 10.25; // Error
getchar();
return 0;
}
error: error C2440: 'initializing' : cannot convert from 'double' to 'foo'
These two forms of initialization are technically different. The first (foo obj(10.25);) is called direct initialization. The second (foo obj = 10.25;) is called copy initialization.
explicit constructors can only be used when you explicitly initialize an object. Direct initialization is one form of explicitly initializing an object. The other form of explicit initialization is the use of a cast.
There is a difference between these two lines of code. The first line,
foo obj(10.25);
explicitly calls your foo constructor passing in 10.25. This syntax, in general, is a constructor call.
The second line,
foo obj2 = 10.25;
tries to implicitly convert from 10.25 to an object of type foo, which would require use of an implicit conversion constructor. In this example, you've marked the constructor explicit, there's no implicit conversion constructor available, and so the compiler generates an error.
Your "not an error" case is an explicit construction. The compiler is doing what you told it to do.
In the first case you are not implicitly converting 10.25 to foo. You are converting it to an int, so it's not an error. Saying foo obj(10.25) is regarded as a direct call to the constructor to initialize a foo object.
In the second case, you are trying to implicitly convert 10.25 to a foo. The constructor marked explicit will not be considered (as you rightfully say), and therefor you will get an error.