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   c o n s t r u c t i o n   3 {\orange{A\ construction\ 3}} A construction 3
A   c o p y   c o n s t r u c t i o n   8 {\orange{A\ copy\ construction\ 8}} A copy construction 8
A   c o p y   c o n s t r u c t i o n   13 {\orange{A\ copy\ construction\ 13}} A copy construction 13
20   a s s i g n m e n t   13 {\orange{20\ assignment\ 13}} 20 assignment 13
A   d e s t r u c t i o n   13 {\orange{A\ destruction\ 13}} A destruction 13
A   d e s t r u c t i o n   8 {\orange{A\ destruction\ 8}} A destruction 8
A   d e s t r u c t i o n   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   c o n s t r u c t i o n   3 {\orange{A\ construction\ 3}} A construction 3
A   c o n s t r u c t i o n   2 {\orange{A\ construction\ 2}} A construction 2
9   a s s i g n m e n t   2 {\orange{9\ assignment\ 2}} 9 assignment 2
A   d e s t r u c t i o n   2 {\orange{A\ destruction\ 2}} A destruction 2
A   d e s t r u c t i o n   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新特性。

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值