13.1 拷贝、赋值与销毁(1)

拷贝构造函数

  如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。

class Foo {
public:
      Foo();  //默认构造函数
      Foo(const Foo&);  //拷贝构造函数
      //...
};

  拷贝构造函数的第一个参数必须是引用类型,虽然我们可以定义一个接受非const引用的拷贝构造函数,但此参数几乎总是一个const的引用。拷贝构造函数在几种情况下都会被隐式地使用。因此,拷贝构造函数通常不应该是explicit的。

  合成拷贝构造函数
  对某些类来说,合成拷贝构造函数用来阻止我们拷贝该类类型的对象,而一般情况,合成的拷贝构造函数会将其参数的成员逐个拷贝到正在创建的对象中。编译器从给定对象中依次将每个非static成员拷贝到正在创建的对象中。

  拷贝初始化
  直接初始化与拷贝初始化的差异:

string dots(10,'.');  //直接初始化
string s(dots);  //直接初始化
string s2=dots;  //拷贝初始化
sttring null_book="9-999-99999-9";  //拷贝初始化
string nines=string(100,'9');  //拷贝初始化

  当使用直接初始化时,我们实际上是要求编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数,当我们使用拷贝初始化时,我们要求编译器将右侧运算对象拷贝到正在创建的对象中,如果需要的话还要进行类型转换。拷贝初始化通常使用拷贝构造函数来完成。
  除了使用“=”定义变量时会发生拷贝初始化,还有以下情况:
  1、将一个对象作为实参传递给一个非引用类型的形参
  2、从一个返回类型为非引用类型的函数返回一个对象
  3、用花括号列表初始化一个数组中的元素或一个聚合类的成员

  拷贝初始化的限制
  如果我们使用的初始化值要求通过一个explicit构造函数来进行类型转换,那么使用拷贝初始化还是直接初始化就不是无关紧要的了:

vector<int> v1(10);  //正确:直接初始化
vector<int> v2=10;  //错误:接受大小参数的构造函数是explicit的
void f(vector<int>);  //f的参数进行拷贝初始化
f(10);  //错误:不能用一个explicit的构造函数拷贝一个实参
f(vecotr<int> (10));  //正确:从一个int直接构造一个临时vector

  编译器可以绕过拷贝构造函数
  在拷贝初始化过程中,编译器可以跳过拷贝/移动构造函数,直接创建对象:

string null_book="9-999-99999-9"  //拷贝初始化

改写为:

string null_book=("9-999-99999-9");  //编译器略过了拷贝构造函数

拷贝赋值运算符

  与类控制其对象如何初始化一样,类也可以控制其对象如何赋值:

Sales_data trans,accum;
trans=accum;  //使用Sales_data的拷贝赋值运算符

  重载赋值运算符
  重载运算符的本质上是函数,其名字由operator关键字后接表示要定义的运算符的符号组成。因此,赋值运算符就是一个名为operator=的函数。例如:

class Foo {
public:
Foo& operator=(const Foo&);  //赋值运算符
//...
};

  合成拷贝赋值运算符
  与处理拷贝构造函数一样,如果一个类未定义自己的拷贝赋值运算符,编译器会为它生成一个合成拷贝赋值运算符。合成拷贝运算符返回一个指向其左侧运算对象的引用。例如:

//等价于合成拷贝赋值运算符
Sales_data&
Sales_data::operator=(const Sales_data &rhs)
{
    bookNo=rhs.bookNo;  //调用string::operator=
    units_sold=rhs.units_sold;  //使用内置的int赋值
    revenue=rhs.revenue;  //使用内置的double赋值
    return *this;  //返回一个此对象的引用
}

析构函数

  析构函数执行与构造函数相反的操作:构造函数初始化对象的非static成员,还可能做一些其他工作;析构函数释放对象使用的资源,并销毁对象的非static数据成员。

class Foo {
public:
      ~Foo();  //析构函数
      //...
};

  由于析构函数不接受参数,因此它不能被重载。

  析构函数完成什么工作
  在一个析构函数中,首先执行函数体,然后销毁成员,成员按初始化顺序的逆序销毁,在对象最后一次使用之后,析构函数的函数体可执行类设计者希望执行的任何收尾工作。在一个析构函数中,不存在类似构造函数中初始化列表的东西来控制成员如何销毁,析构部分是隐式的。

  什么时候会调用析构函数
  无论何时一个对象被销毁,就会自动调用其析构函数,由于析构函数自动运行,我们的程序可以按需要分配资源,而无须担心何时释放这些资源。

  合成析构函数
  当一个类未定义自己的析构函数时,编译器会为它定义一个合成析构函数。对于某些类,合成析构函数被用来阻止该类型的对象被销毁,如果不是这种情况,合成析构函数的函数体就为空。
  在(空)析构函数执行完毕后,成员会被自动销毁,析构函数自身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段被销毁的,在整个对象销毁过程中,析构函数体是作为成员销毁步骤之外的另一部分而进行的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352