C++拷贝控制(copy control)

拷贝、赋值、销毁

构造函数 ⇒ 对象初始化行为
赋值运算符 ⇒ 对象间赋值行为
析构函数 ⇒ 销毁行为

拷贝构造函数

copy constructor:第一个参数为自身(几乎都为const)的引用,额外参数都有默认值的构造函数
拷贝初始化
直接初始化=函数匹配
拷贝初始化=运算 (copy initialization) ⇒ 拷贝构造函数 or 移动构造函数
1."="定义变量
2.实参传递非引用形参
3.返回非引用对象
4.{list}初始化数组或聚合类

class mycl
{
public:
   int a=0;
   mycl(int i):a(i){cout<<"constructor!"<<endl;}
   mycl(const mycl &c):a(c.a){cout<<"copy constructor!"<<endl;}
   ~mycl(){cout<<"destructor!"<<endl;}
};
mycl fun(const mycl &m)
{
    cout<<"before copy"<<endl;
    mycl mtmp(m);
     cout<<"after copy"<<endl;
    return mtmp;  //这里返回mtmp到main时
} 
int main()    
{
    int a=0;
    mycl m1(a);
    mycl m2=fun(m1);
    return 0;                
}

在这里插入图片描述
通常g++(大多数编译器)默认开启RVO(return value optimization),从而看不到构造临时返回变量的拷贝构造过程,可以通过"-fno-elide-constructors"命令关闭,还原拷贝构造返回值的过程
在这里插入图片描述
explict
explicit声明的函数只能直接初始化

class ClassA
{
public:
explicit ClassA(string s){}  
//explicit只能声明在class内部 且只能作用于单变量构造函数
//此时无法完成ClassA a("123")中const char*到string的隐式转换
}
static_cast<ClassA>(s); 
//可以显示强制转化使用string构造一个ClassA临时变量

拷贝构造函数在很多情况下是隐式使用的,因此不能是explicit的
不管有没有定义,编译器都会合成拷贝构造函数(synthesized copy constructor):会逐个拷贝数组
但有些情况并不希望某些对象能被拷贝(如istream类)

拷贝赋值运算符

copy-assignment operator:类未定义时编译器代为合成
部分运算符重载必须定义为成员函数(如“=”),左侧运算对象隐式绑定this,右侧显示传递参数

//等效合成拷贝赋值运算符
C& operator=(const C &r)
{   
    mem=r.mem;    //将每个非static成员赋予左对象成员,操作我自己
    return *this; //返回指向对象本身的引用,返回我自己
}

指向对象的引用或指针离开作用域时,其指向的对象并不会执行析构函数,需要delete
析构函数自身并不直接销毁成员,成员是在执行完析构函数体后的析构阶段被销毁的

三五法则
拷贝构造+拷贝赋值运算符+析构+移动构造+移动赋值
析构 ⇒(拷贝构造+赋值拷贝构造)= 成套定义
尤其注意:需要析构则一定要 拷贝构造函数 和 赋值拷贝运算符

class HasPtr
{
public:
string *p;
HasPtr(const string &s=string()):p(new string(s)){}
~HasPtr(){delete p;}
}
HasPtr fun(HasPtr h)
{
  HasPtr r=h;  
  //使用了合成拷贝构造和赋值拷贝运算符,指针只是简单的被拷贝指向同一地址
  return r;    
  //返回值后r和h均被销毁,但此时析构函数delete p两次,未定义的错位结果
}

阻止拷贝

如iostream类,定义多个对象将导致多个对象写入或读取相同的IO缓冲
通过"删除函数(deleted function)"来阻止拷贝

 class C
 {
 public:
     C()=default;
     C(const C &)=delete;  
     //必须出现在第一次声明的时候=delete(预编译检查),防止被使用
     C& operator=(const C &)=delete;
     ~C()=default;    
     //析构函数不能(无法通过编译)delete,否则无法销毁对象
 }

当存在不能拷贝、赋值或销毁的成员时,则类的合成控制函数=delete
C11之前:通过将拷贝构造和赋值运算符声明为private但不定义实现阻止拷贝

 class C
 {
     C(const C &); 
     C& operator=(const C &);
 public:
     C()=default;
     ~C()=default; 
 }
能用delete用delete!!! 能用delete用delete!!! 能用delete用delete!!!

移动构造函数

move constructor

移动赋值运算符

move-assignment operator

析构函数

destructor

对象移动

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值