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
    )。但这实际上是一个错误,因为