Copy constructor called everytime a default constructor is called?
I was going through some of the questions on constructor initialization list when I bumped into this.
Consider this:
class Student {
public:
Student() {
id = 0;
}
Student(int i) {
id = i;
}
private:
int id;
};
Now, check this out:
By the time you get in the body of the constructor, all fields have already been constructed; if they have default constructors, those were already called. Now, if you assign a value to them in the body of the constructor, you are calling the copy constructor. That is inefficient, because two constructors end up being called instead of one.
Source: What does a colon following a C++ constructor name do?
So, does it mean that when I call the parameter-less constructor, the copy constructor is also being called?
Please explain. This is really confusing.
Particularly the meaning of the first line:
By the time you get in the body of the constructor, all fields have already been constructed
It means that int id
has already been initialized before you get to the line id = 0
. Because no explicit initializer has been specified, it has been default initialized. Additionally, because it is an int
, the initialization rules tell use that it will have some indeterminate value.
In practice, for an int
, or any type that is extremely cheap to initialize, this doesn't matter too much.
If instead of using an int
member, we used a class, we could more clearly see what is actually going on behind the scenes:
#include <iostream>
class Verbose {
public:
Verbose() {
std::cout << __PRETTY_FUNCTION__ << "n";
}
Verbose(int) {
std::cout << __PRETTY_FUNCTION__ << "n";
}
Verbose(Verbose const &) {
std::cout << __PRETTY_FUNCTION__ << "n";
}
Verbose & operator=(Verbose const &) {
std::cout << __PRETTY_FUNCTION__ << "n";
return *this;
}
~Verbose() {
std::cout << __PRETTY_FUNCTION__ << "n";
}
};
class Object {
public:
Verbose v;
Object() {
v = Verbose(3);
}
};
int main() {
Object o;
}
This code will output:
Verbose::Verbose()
Verbose::Verbose(int)
Verbose &Verbose::operator=(const Verbose &)
Verbose::~Verbose()
Verbose::~Verbose()
Note that we:
v
. Verbose(3)
Object o
goes out of scope, we then destroy the member variable. Note that we basically constructed Verbose v
twice! We first used the default constructor, and then we basically rebuilt it using the operator=
call. If we used an initializer list, we could reduce that down to one call to Verbose(int)
.
They mean this
Student() {
id = 0;
}
Is less efficient than
Student() : id(0) {}
In this particular example, id
would be initialized in a single step since the member is just an int
.
In contrast, the latter method would make a difference if Student
had more complex members, like perhaps Backpack
and Books
. If these classes weren't POD, the first method would take two steps to initialize the member, and the second would only take one step to initialize.
上一篇: 定义的行为警告?
下一篇: 每次调用一个默认构造函数时调用构造函数?