I read in http://www.cs.technion.ac.il/users/yechiel/c++-faq/init-lists.html
that using initializer lists is more efficient than doing assigment in the body of the constructor, because for example in Fred::Fred() { x_ = whatever; }
1) the expression whatever causes a separate, temporary object to be created, and this temporary object is passed into the x_ object's assignment operator. Then that temporary object is destructed at the ;
2)the member object will get fully constructed by its default constructor, and this might, for example, allocate some default amount of memory or open some default file
How can assigment cause the creation of some temporary object inside the constructor? That means that the Construtor would call itself: an infinite recursive call
I made the following piece of code to verify a copy of the object is created in the assigment process,hoping to see the additional creation and destruction of the temporary object but all I can see is the creating and destruction of the object I am creating in the main an of course no infinite recursive call.
How do I make sense of it and how can I modify the code to see the creation and destruction of the temporary object?
#include<iostream>
using namespace std;
class Base
{
private:
int c_var;
public:
Base( )
{ c_var=10;
cout <<"Constructor called"<<endl;
cout << "Value is " << c_var<<endl;
}
~Base()
{
cout <<"Destructor called"<<endl;
}
};
int main()
{
Base il;
}
How can assigment cause the creation of some temporary object inside the constructor? That means that the Construtor would call itself: an infinite recursive call
No. The text talks about calling the constructor of the member. With an int it doesn't matter too much, but consider:
struct foo {
foo() {
/* construct a foo, with expensive instructions */
std::cout << "default constructor";
}
foo(int x) {
/* also construct a foo */
std::cout << "constructor";
}
};
struct bar_wrong {
foo f;
bar_wrong() {
f = foo(42);
}
};
Members are initialized before the body of the constructor is executed. Hence the foo member of bar_wrong will first be default constructed (which is potentially expensive) just to be overwritten with the right instance later and creating a bar_wrong will print both outputs from foos constructors.
The correct way is
struct bar_correct {
foo f;
bar_correct() : f(42) {}
};
Because here foo is only initialized. Alternatively you can use in-class initializers:
struct bar_alternative {
foo f{42};
};
Here the compiler generated constructor is sufficient. It will use the in-class initializer to initialize f with 42.
Related
in C++, what is the difference between initialization list and assigning values in a constructer rather than the way each method looks?
I mean what's the advantage of using one rather than the other and why in the given example in the slide (below) only works with initialization? (I hope if you could add some resources to it since I didn't find)
Click here to view slide: uploaded on imgur
Using initialization list in constructor is the one step process i.e. it initializes objects at the moment it’s declared. It calls copy constructor.
Whereas using assignment is the two-step process i.e. define the object and then assign it. Defining objects calls default constructor and then assignment calls assignment operator. Hence, expensive operations.
In C++, constant or reference data member variables of a class can only be initialized in the initialization list, not using assignment in constructor body.
Both constant and reference data member variables have property that they both must be initialized at the moment of declaration. So, there is only way to use initialization list in constructor, as initialization list initializes class member variables at the time of declaration whereas assignment if constructor body initializes data members after declaration.
There are situations where initialization of data members inside constructor doesn’t work and Initializer List must be used. Following are such cases.
For initialization of non-static const data members.
#include<iostream>
using namespace std;
class Test {
const int t;
public:
Test(int t):t(t) {} //Initializer list must be used
int getT() { return t; }
};
int main() {
Test t1(10);
cout<<t1.getT();
return 0;
}
For initialization of reference members.
#include<iostream>
using namespace std;
class Test {
int &t;
public:
Test(int &t):t(t) {} //Initializer list must be used
int getT() { return t; }
};
int main() {
int x = 20;
Test t1(x);
cout<<t1.getT()<<endl;
x = 30;
cout<<t1.getT()<<endl;
return 0;
}
For initialization of member objects which do not have default constructor. (In your case Array digits does not have default constructor)
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int );
};
A::A(int arg) {
i = arg;
cout << "A's Constructor called: Value of i: " << i << endl;
}
// Class B contains object of A
class B {
A a;
public:
B(int );
};
B::B(int x):a(x) { //Initializer list must be used
cout << "B's Constructor called";
}
int main() {
B obj(10);
return 0;
}
For initialization of base class members.
When constructor’s parameter name is same as data member.
For Performance reasons.
If you don't use an initialization list, the data members of the class will be default constructed before the body of the constructor is reached:
class Foo{
private:
int bar;
public:
Foo(int _bar){//bar is default constructed here
bar = _bar; //bar is assigned a new value here
}
};
This isn't a big issue for a fundamental-type, like int, as the default constructor is not expensive. However, it can become an issue if the data member does not have a default constructor, or default construction followed by assignment is more expensive than direct construction:
//Bar does not have a default constructor, only a copy constructor
class Bar{
public:
Bar() = delete; //no default constructor
Bar(const Bar& bar); //copy constructor only
};
class Foo{
private:
Bar bar;
public:
Foo(const Bar& _bar){
//this will not compile, bar does not have a default constructor
// or a copy assignment operator
bar = _bar;
}
Foo(const Bar& _bar) : bar(_bar){//this will compile, copy constructor for bar called
}
};
Generally speaking, use the initialization list for more efficient code.
I was trying the following program :
#include <iostream>
using namespace std;
class Type{
int i;
public:
Type() {cout << "type constructor "<<endl;}
Type (const Type &) { cout << "type copy constructor called" << endl;}
};
class MyClass {
Type variable;
public:
MyClass(Type a) {
cout << "inside MyClass constructor "<<endl;
variable = a;
}
};
void fun (Type){
return;
}
int main (){
Type t;
cout <<"t created"<<endl;
MyClass tmp = MyClass(t);
cout<<"calling fun"<<endl;
fun(t);
}
The output of this is :
type constructor
t created
type copy constructor called
type constructor
inside MyClass constructor
calling fun
type copy constructor called
I am wondering why default constructor is called when I pass it to MyClass constructor and why copy constructor is called when I pass it to fun()?
BTW same happens when I use initializer list.
I am wondering why default constructor is called when I pass it to MyClass constructor
It has nothing to do with passing argument here. As a member variable, variable will be default constructed at first.
class MyClass {
Type variable;
public:
MyClass(Type a) { // variable will be default constructed at first, since it's not initialized via member initializer list
cout << "inside MyClass constructor "<<endl;
variable = a; // then variable is assgined via assignment operator
}
};
You can specify how variable would be initialized by member intializer list, like
class MyClass {
Type variable;
public:
MyClass(Type a) : variable(a) { // variable will be direct initialized via copy constructor
cout << "inside MyClass constructor "<<endl;
// variable = a; // no need for assignment
}
};
The default constructor won't be called for this case.
Copy constructor is invoked for both the parameters (the one for MyClass constructor and the one for fun) and the logs you posted report that.
In fact, you have two times the following line:
type copy constructor called
Default constructor is invoked for data member variable, for it is not explicitly initialized.
The same happens if you use an initializer list like this:
MyClass(Type a): variable{} {
//...
}
Actually, variable is default initialized if you don't have any initializer list, so there is no reason to expect a different log.
I know how to write a copy constructor when you have raw pointer data members in a class, but how do you write a copy constructor when you manage these with a shared_ptr?
Is there a copy() or clone() function which should be called? Interestingly I have never seen such an example.
The copy constructor for std::shared_ptr creates a second pointer which shared ownership with the first pointer. The pointee will be destroyed when all std::shared_ptr that point to it are destroyed.
Without a copy constructor explicitly declared, the language specification decrees that a suitable one will be implicitly provided, and that it will call the copy constructors of each member of your class.
So, in other words, the implicit copy constructor provided for your class will call shared_ptr<T>::shared_ptr(const shared_ptr<T> &), which will create a second share pointer pointing to the same object, and it doesn't look like that's what you want. If you want a deep copy of the pointee, you will have to declare your own copy constructor that creates one:
class Foo
{
Foo(const Foo &other)
: foobar(new Bar(*other.foobar.get()))
{}
shared_ptr<Bar> foobar;
}
References:
std::shared_ptr constructor documentation
Copy constructor semantics in C++98 (see section 12.8.8) and C++11 (see section 12.8.16)
std::shared_ptr has its own copy constructor that will handle the reference counting of the managed shared data.
struct Foo {
Foo(int i) : ptr{std::make_shared<int>(i)} {}
std::shared_ptr<int> ptr;
};
int main() {
Foo f1{0};
Foo f2{f1}; // Using the implicitly generated copy ctor.
*f1.ptr = 1;
std::cout << *f1.ptr << std::endl; // 1 (data is shared).
std::cout << *f2.ptr << std::endl; // 1 (data is shared).
}
If you want your class to have resource ownership semantics then simply declare the resource as an object with automatic storage duration.
struct Foo2 {
Foo2(int i) : i{i} {}
int i; // Automatic object.
};
int main() {
Foo2 f1{0};
Foo2 f2{f1};
f1.i = 1;
std::cout << f1.i << std::endl; // 1
std::cout << f2.i << std::endl; // 0
}
Say a given class A is defined with a public copy constructor and a private move constructor. If a function f returns an object of type A, and f is used to initialize a local instance of variable of type A, then by default (since the value returned is a rvalue) the compiler will try to use the move constructor. I believed it is sensible to expect the compiler to use the copy constructor once it detects that the move constructor is private, however to my surprise I received a compiler error stating that the move constructor is private. My question is as follows, given the following code:
#include<iostream>
using namespace std;
class A
{
friend A f();
public:
A(const A&) { cout << "copy\n"; }
private:
A() {}
A(A&&) { cout << "move\n"; }
};
A f()
{
A a;
return a;
}
int main()
{
A a = f();
}
How can I change the code (without changing A or f) so that I could initialize the variable in main using the copy constructor?
I would change the class since it's not sensible.
Alternatively derive from the class or wrap it.
If you just want a quick hack you can do
template< class Type >
Type& tempref( Type&& t ) { return t; }
then do
A a = tempref( f() )
Disclaimer: code not touched by compiler's hands.
The overload resolution is performed first, to select a function to call.
Access check is performed as a later step, checking if the selected function/constructor is possible to call.
This is done on purpose, so a private function is not called (because it is private). Having the compiler select another function to call in that case would not be productive.
My understanding of constructor chaining is that , when there are more than one constructors in a class (overloaded constructors) , if one of them tries to call another constructor,then
this process is called CONSTRUCTOR CHAINING , which is not supported in C++ .
Recently I came across this paragraph while reading online material.... It goes like this ...
You may find yourself in the situation where you want to write a member function to re-initialize a class back to default values. Because you probably already have a constructor that does this, you may be tempted to try to call the constructor from your member function. As mentioned, chaining constructor calls are illegal in C++. You could copy the code from the constructor in your function, which would work, but lead to duplicate code. The best solution in this case is to move the code from the constructor to your new function, and have the constructor call your function to do the work of initializing the data.
Does a member function calling the constructor also come under constructor chaining ??
Please throw some light on this topic in C++ .
C++11 allows constructor chaining (partially). This feature is called "delegating constructors". So in C++11 you can do the following
class Foo
{
public:
Foo(int a) : Foo() { _a = a; }
Foo(char* b) : Foo() { _b = b; }
Foo() { _c = 1.5; }
private:
int _a = 0;
char* _b = nullptr;
double _c;
};
However, there is a severe limitation that a constructor that calls another constructor is not allowed to initialize any other members. So you cannot do the following with a delegating constructor:
class Foo
{
public:
Foo(int a) : Foo(), _a(a) { }
Foo(char* b) : Foo(), _b(b) { }
Foo() { _c = 1.5; }
private:
int _a = 0;
char* _b = nullptr;
double _c;
};
MSVC++2013 gives compile error "C3511: a call to a delegating constructor shall be the only member-initializer" for the latter code example.
The paragraph basically says this:
class X
{
void Init(params) {/*common initing code here*/ }
X(params1) { Init(someParams); /*custom code*/ }
X(params2) { Init(someOtherParams); /*custom code*/ }
};
You cannot call a constructor from a member function either. It may seem to you that you've done it, but that's an illusion:
class X
{
public:
X(int i):i(i){}
void f()
{
X(3); //this just creates a temprorary - doesn't call the ctor on this instance
}
int i;
};
int main()
{
using std::cout;
X x(4);
cout << x.i << "\n"; //prints 4
x.f();
cout << x.i << "\n"; //prints 4 again
}
That's not what the text says. It's suggesting your constructor call a member function which is normal and legal. This is to avoid explicitly calling the ctor again and to avoid duplicating code between your ctor and reset function.
Foo::Foo() {
Init();
}
void Foo::Reset() {
Init();
}
void Foo::Init() {
// ... do stuff ...
}
I'm not sure if it (calling a constructor from a member function) will work or not, but it's a bad practice. moving the initialize code to a new function is the logic way.
Basically saying, Don't call the constructor unless you constructing...
when we call constructor from a member function, then it will temporary create a object of its type.
in case if we are calling in derived class function then all the parent constructors are also gets executed and destroyed using destructor once function goes out of scope.
its not a Good Practice to call the constructors in member functions since it creates objects of every class derived.