关于复制构造函数的学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/abc15766228491/article/details/84886774

注:以下概念来自《c++ primer中文版》(第四版)

复制构造函数概念:

  1. 复制构造函数:是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。

复制构造函数可以用于:

  1. 根据另一个同类型的对象显式或隐式初始化一个对象。
  2. 复制一个对象,将它作为实参传给一个函数。
  3. 从函数返回时复制一个对象。
  4. 初始化顺序容器中的元素。
  5. 根据元素初始化式列表初始化数组元素。

根据上面的5点,分别得到下面的例子:

#include <iostream>
#include <vector>
using namespace std;
class Person{
public:
    Person(string name_, int age_);
    Person(const Person &p);
private:
    string name;
    int age;
};
Person::Person(string name_, int age_):name(name_), age(age_){
    cout<<"constructor name is:"<<name<<"\t\t\t"<<"constructor called"<<endl;
}
Person::Person(const Person &p) {
    cout<<"copy name is:"<<p.name<<"\t\t\t"<<" copy-constructor call"<<endl;
    name = p.name;
    age = p.age;
}
// 如果这里是void get_Person(Person &p) 则不会调用复制构造函数,所以为了节省复制构造函数调用时间,可以将函数形参设置为const Person &p。
void  get_Person(Person p)
{
    Person temp_p("temp_p", 12);
    return ;
}
int main()
{
    Person p1("p1", 12);
    Person p2 = p1;               // 1、根据另一个同类型的对象显式或隐式初始化一个对象
    get_Person(p2);               // 2、复制一个对象,将它作为实参传给一个函数
    vector<Person> v_p;
    v_p.push_back(Person("p3", 12));    // 3、初始化容器中的元素
    Person p4("p4", 12);
    Person A_p[] = {Person("p5", 12), p4};    // 4、根据元素初始化列表初始化数组元素。。这里只有p4用了copy构造函数

}
constructor name is:p1			constructor called
copy name is:p1			 copy-constructor call
copy name is:p1			 copy-constructor call
constructor name is:temp_p			constructor called
constructor name is:p3			constructor called
copy name is:p3			 copy-constructor call
constructor name is:p4			constructor called
constructor name is:p5			constructor called
copy name is:p4			 copy-constructor call

对于上面的第3点,在clion和dev下的运行结果和 Visual Studio的结果不同,单独说明(以下例子来源:郭炜老师《c++面向对象程序设计》课程)

例子:

// 从函数返回复制一个对象时,需要调用复制构造函数
#include <iostream>
using namespace std;
class A{
public:
    int x;
    A(int x_):x(x_){
        cout<<x<<" constructor called"<<endl;
    }
    A(const A &a){
        x = 2+a.x;
        cout<<" copy call"<<endl;
    }
    ~A(){
        cout<<x<<" destructor called"<<endl;
    }
};
A func()
{
    A b(10);
    return b;
}
int main()
{
    A a(1);
    // 这里应该会调用拷贝构造函数,返回的a的值应该是a.x=12
    a = func();
    // 执行构造函数和析构函数的顺序如下:
    /*
     1、执行a(1)的构造函数
     2、执行func里面的b(10)的构造函数
     3、返回b的时候会执行复制构造函数,此时已经复制了一个新的成员,这个函数的x值为12
     4、返回之后执行b的析构函数
     5、执行 a = func() 语句,对a重新赋值,赋值语句不调用复制构造函数
     6、执行复制的临时对象的析构函数
     7、执行a的析构函数
     */
    return 0;
}

在Linux下的Clion的结果:

1 constructor called
10 constructor called
10 destructor called
10 destructor called

在windows下的dev结果:

1 constructor called
10 constructor called
10 destructor called
10 destructor called

在windows下的Visual Studio的结果:

windows_copy

按照概念,只有Visual Studio上面的结果是正常的。

解释一下linux下的clion和windows下的dev出现的异常结果:从结果上来看,func并没有产生临时对象,也就是说,并没有执行复制构造函数。

Linux下的clion和dev的过程如下:

  1. 执行构造函数。
  2. 执行func里的b的构造函数。
  3. 返回时执行b的析构函数。
  4. 将返回的结果复制给a,然后执行a的析构函数。

根据郭老师讲的,原因是(dev c++)对程序编译时做了优化,认为func里面返回了b,如果调用复制构造函数,会浪费时间,因此直接返回了b的结果。

个人猜测,linux下的clion同样进行了优化。

猜你喜欢

转载自blog.csdn.net/abc15766228491/article/details/84886774