zoukankan      html  css  js  c++  java
  • 不要轻视拷贝构造函数与赋值函数

    不要轻视拷贝构造函数与赋值函数

    由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数
      有些轻视。请先记住以下的警告,在阅读正文时就会多心:
      ?? 如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”
      的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐
      含了错误。以类String 的两个对象a,b 为例,假设a.m_data 的内容为“hello”,
      b.m_data 的内容为“world”。
      现将a 赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。
      这将造成三个错误:一是b.m_data 原有的内存没被释放,造成内存泄露;二是
      b.m_data 和a.m_data 指向同一块内存,a 或b 任何一方变动都会影响另一方;三
      是在对象被析构时,m_data 被释放了两次。
      ?? 拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对
      象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三
      个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋
      值函数吗?
      String a(“hello”);
      String b(“world”);
      String c = a; // 调用了拷贝构造函数,最好写成 c(a);
      c = b; // 调用了赋值函数
      本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。
      类String 的拷贝构造函数与赋值函数
      // 拷贝构造函数
      String::String(const String &other)   所有构造函数无返回值
      {
      // 允许操作other 的私有成员m_data
      int length = strlen(other.m_data);
      m_data = new char[length+1];
      strcpy(m_data, other.m_data);
      }
      // 赋值函数
      String & String::operator =(const String &other)
      {
      // (1) 检查自赋值
      if(this == &other)
      return *this;
      // (2) 释放原有的内存资源
      delete [] m_data;
      // (3)分配新的内存资源,并复制内容
      int length = strlen(other.m_data);
      m_data = new char[length+1];
      strcpy(m_data, other.m_data);
      // (4)返回本对象的引用
      return *this;
      }
      类String 拷贝构造函数与普通构造函数的区别是:在函数入口处无
      需与NULL 进行比较,这是因为“引用”不可能是NULL,而“指针”可以为NULL。
      类String 的赋值函数比构造函数复杂得多,分四步实现:
      (1)第一步,检查自赋值。你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这
      样的自赋值语句!的确不会。但是间接的自赋值仍有可能出现,例如
      // 内容自赋值
      b = a;
      …
      c = b;
      …
      a = c;
      // 地址自赋值
      b = &a;
      …
      a = *b;
      也许有人会说:“即使出现自赋值,我也可以不理睬,大不了化点时间让对象复制
      自己而已,反正不会出错!”
      他真的说错了。看看第二步的delete,自杀后还能复制自己吗?所以,如果发现自
      赋值,应该马上终止函数。注意不要将检查自赋值的if 语句
      if(this == &other)
      错写成为
      if( *this == other)
      (2)第二步,用delete 释放原有的内存资源。如果现在不释放,以后就没机会了,将
      造成内存泄露。
      (3)第三步,分配新的内存资源,并复制字符串。注意函数strlen 返回的是有效字符
      串长度,不包含结束符‘’。函数strcpy 则连‘’一起复制。
      (4)第四步,返回本对象的引用,目的是为了实现象 a = b = c 这样的链式表达。注
      意不要将 return *this 错写成 return this 。那么能否写成return other 呢?效果
      不是一样吗?
      不可以!因为我们不知道参数other 的生命期。有可能other 是个临时对象,在赋
      值结束后它马上消失,那么return other 返回的将是垃圾。
      偷懒的办法处理拷贝构造函数与赋值函数
      如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的
      缺省函数,怎么办?
      偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。
      例如:
      class A
      { …
      private:
      A(const A &a); // 私有的拷贝构造函数
      A & operate =(const A &a); // 私有的赋值函数
      };
      如果有人试图编写如下程序:
      A b(a); // 调用了私有的拷贝构造函数
      b = a; // 调用了私有的赋值函数
      编译器将指出错误,因为外界不可以操作A 的私有函数。(王朝网络 wangchao.net.cn)

  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/skyofbitbit/p/3569421.html
Copyright © 2011-2022 走看看