C++ 每次调用默认构造函数时都调用复制构造函数?
当我遇到这个问题时,我正在浏览构造函数初始化列表中的一些问题 考虑这一点:C++ 每次调用默认构造函数时都调用复制构造函数?,c++,C++,当我遇到这个问题时,我正在浏览构造函数初始化列表中的一些问题 考虑这一点: class Student { public: Student() { id = 0; } Student(int i) { id = i; } private: int id; }; 现在,看看这个: 当您进入构造器主体时,所有字段都已构造完毕;如果它们有默认构造函数,那么它
class Student {
public:
Student() {
id = 0;
}
Student(int i) {
id = i;
}
private:
int id;
};
现在,看看这个:
当您进入构造器主体时,所有字段都已构造完毕;如果它们有默认构造函数,那么它们已经被调用了。现在,如果在构造函数体中为它们赋值,则调用的是复制构造函数。这是低效的,因为最终调用了两个构造函数而不是一个
资料来源:
那么,这是否意味着当我调用无参数构造函数时,也会调用复制构造函数?
请解释一下。这真令人困惑
特别是第一行的含义:
当您进入构造函数主体时,所有字段都已经被构造好了
这意味着在到达行
id=0
之前,int-id
已经初始化。由于未指定显式初始值设定项,因此它已默认初始化。此外,由于它是一个int
,初始化规则告诉use它将有一些不确定的值
在实践中,对于int
,或任何初始化成本极低的类型,这并不重要
如果不使用int
成员,而是使用类,我们可以更清楚地看到幕后的实际情况:
#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;
}
请注意,我们:
v
Verbose(3)
对象o
超出范围时,我们将销毁成员变量注意,我们基本上构建了两次
Verbose v
!我们首先使用默认构造函数,然后基本上使用操作符=
调用重新构建它。如果我们使用了,我们可以将其减少为一个对Verbose(int)
的调用,这意味着intid
在到达行id=0
之前已经初始化。由于未指定显式初始值设定项,因此它已默认初始化。此外,由于它是一个int
,初始化规则告诉use它将有一些不确定的值
在实践中,对于int
,或任何初始化成本极低的类型,这并不重要
如果不使用int
成员,而是使用类,我们可以更清楚地看到幕后的实际情况:
#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;
}
请注意,我们:
v
Verbose(3)
对象o
超出范围时,我们将销毁成员变量Verbose v
!我们首先使用默认构造函数,然后基本上使用操作符=
调用重新构建它。如果我们使用了,我们可以将其减少到一个调用Verbose(int)
他们的意思是这样的
Student() {
id = 0;
}
效率不如
Student() : id(0) {}
在这个特定的示例中,id
将在一个步骤中初始化,因为成员只是一个int
相反,如果学生
有更复杂的成员,比如背包
和书籍
,则后一种方法会有所不同。如果这些类不是POD,第一个方法将采取两个步骤来初始化成员,第二个方法只采取一个步骤来初始化
Student() {
id = 0;
}
效率不如
Student() : id(0) {}
在这个特定的示例中,id
将在一个步骤中初始化,因为成员只是一个int
相反,如果
学生
有更复杂的成员,比如背包
和书籍
,则后一种方法会有所不同。如果这些类不是POD,第一个方法将采取两个步骤来初始化成员,第二个方法只采取一个步骤来初始化。“那么,这是否意味着当我调用无参数构造函数时,也会调用复制构造函数?”不。cite的状态是什么?这不是一个很好的例子,因为int
是一个POD,因此不是“默认构造的”。请解释一下它的意图。何时调用两个构造函数而不是一个。我真的很困惑。它们指的是成员的副本构造函数(如果它们是类类型而不是int
)。但这实际上是一个错误,因为所谓的是赋值运算符,而不是复制构造函数。主要问题是你引用了一个不太正确的答案。首先,将“所有字段”替换为“所有成员变量”。其次,“如果在构造函数体中为它们赋值,则调用的是复制构造函数”不是真的。实际上,您是在调用默认构造函数之后调用赋值运算符的。不存在对同一对象调用两个构造函数的情况。除非一个构造函数显式地转发给另一个构造函数,否则它没有意义。“那么,这是否意味着当我调用无参数构造函数时,复制构造函数也会被调用?”不。引用的状态是什么?这不是一个很好的示例,因为int
是一个POD,因此不是“默认构造的”.请解释一下你的意图。何时调用两个构造函数而不是一个。我真的很困惑。它们指的是成员的副本构造函数(如果它们是类类型而不是int
)。但这实际上是一个错误,因为