C/C++:复制构造函数

1−复制构造函数又称拷贝构造函数{\red{1-复制构造函数又称拷贝构造函数}}1

2−赋值构造函数必须传引用,若传值则会无限递归,爆堆栈{\red{2-赋值构造函数必须传引用,若传值则会无限递归,爆堆栈}}2


C++中,三种调用复制构造函数的情况:

一个对象以值传递的方式传入函数体{\red{一个对象以值传递的方式传入函数体}}

一个对象以值传递方式从函数返回{\orange{一个对象以值传递方式从函数返回}}

一个对象需要通过另一个对象初始化{\green{一个对象需要通过另一个对象初始化}}


自定义复制构造函数的意义:

当类对象的成员使用堆内存,且可能会出现上述三种情况时,需要自定义复制构造函数。

默认复制构造函数只是指针内容上的复制,但并不会复制堆内存。


复制构造函数与赋值函数的区别:

复制构造是用一个对象来初始化一块内存区域{\red{复制构造是用一个对象来初始化一块内存区域}}
赋值函数是对于一个已经初始化的对象来修改{\orange{赋值函数是对于一个已经初始化的对象来修改}}

复制构造和析构函数是成对儿的{\red{复制构造和析构函数是成对儿的}}
赋值函数不会与析构函数成对儿{\green{赋值函数不会与析构函数成对儿}}

复制构造大多数情况是深拷贝{\red{复制构造大多数情况是深拷贝}}
赋值函数大多数是引用{\blue{赋值函数大多数是引用}}


关于复制构造《编译器版本,Apple clang 11.0.0》:

示例一,将参数返回重新赋值,调用复制构造函数{\red{示例一,将参数返回重新赋值,调用复制构造函数}}

class A{
public:
    int v; 															// 成员变量
    A(int t){ 														// 构造函数
        v = t;
        cout<<"A construction "<<v<<endl;
    }
    A(A &a){														//	复制构造
        v = a.v + 5;
        cout<<"A copy construction "<<v<<endl;
    }
    A& operator = (const A &a){						// 赋值函数 
        this->v = a.v + 7;
        cout<<this->v<<" assignment "<<a.v<<endl;
        return *this;
    }
    ~A(){															// 析构函数
        cout<<"A destruction "<<v<<endl;
    }
};

A fun(A a){ return a; }

int main(){
    A a(3);
    a = fun(a);
    return 0;
}

输出{\orange{输出}}
A construction 3{\orange{A\ construction\ 3}}A construction 3
A copy construction 8{\orange{A\ copy\ construction\ 8}}A copy construction 8
A copy construction 13{\orange{A\ copy\ construction\ 13}}A copy construction 13
20 assignment 13{\orange{20\ assignment\ 13}}20 assignment 13
A destruction 13{\orange{A\ destruction\ 13}}A destruction 13
A destruction 8{\orange{A\ destruction\ 8}}A destruction 8
A destruction 20{\orange{A\ destruction\ 20}}A destruction 20

说明一下执行顺序:{\red{说明一下执行顺序:}}

  • A a(3); 调用自定义构造函数A(int),成员为3
  • main函数变量“a”传入fun函数,复制构造fun函数参数“a”,此时成员为8
  • 将fun函数参数“a”返回,复制构造临时变量“b”,此时成员为13,代码变为a = b;
  • 由于main函数变量"a"已经初始化,此时赋值函数将b赋值给a,a成员为20
  • a = fun(a);执行完毕,fun函数退出函数栈,按栈的方式逐一销毁fun函数变量,临时变量b<成员13>销毁,参数a<成员8>销毁
  • main函数执行完毕,退出函数栈,main函数变量a<成员20>销毁

示例二,将函数内变量返回,不调用复制构造{\red{示例二,将函数内变量返回,不调用复制构造}}

class A{
public:
    int v;
    A(int t){
        v = t;
        cout<<"A construction "<<v<<endl;
    }
    A(A &a){
        v = a.v + 5;
        cout<<"A copy construction "<<v<<endl;
    }
    A& operator = (const A &a){
        this->v = a.v + 7;
        cout<<this->v<<" assignment "<<a.v<<endl;
        return *this;
    }
    ~A(){
        cout<<"A destruction "<<v<<endl;
    }
};
A fun(){
    A a(2);
    return a;
}
int main(){
    A a(3);
    a = fun();
    return 0;
}

输出{\orange{输出}}
A construction 3{\orange{A\ construction\ 3}}A construction 3
A construction 2{\orange{A\ construction\ 2}}A construction 2
9 assignment 2{\orange{9\ assignment\ 2}}9 assignment 2
A destruction 2{\orange{A\ destruction\ 2}}A destruction 2
A destruction 9{\orange{A\ destruction\ 9}}A destruction 9

这里返回a不调用复制构造感觉是编译器做的优化,我也不知道为啥?{\red{这里返回a不调用复制构造感觉是编译器做的优化,我也不知道为啥?}}a


情况三,参数返回构造新示例,返回值不生成临时变量{\red{情况三,参数返回构造新示例,返回值不生成临时变量}}

class A{
public:
    static int num;
    A(){num++;}
    void print(){cout<<num<<endl;}
    ~A(){num--;print();}
};

int A::num = 0;

A fun(A b){
    b.print();
    return b;
}

int main(){
    A a;
    a.print();
    A c = fun(a);
    c.print();
    return 0;
}

输出:{\orange{输出:}}: 1 1 0 0 -1 -2

也是编译器优化?哭晕在厕所,搞不懂{\red{也是编译器优化?哭晕在厕所,搞不懂}}


2019−07−04更新:{\green{2019-07-04更新:}}20190704

当右值是临时变量时,构造可能采用移动构造优化,C++11新特性。

移动构造,浅拷贝且临时变量空间不销毁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值