zoukankan      html  css  js  c++  java
  • C++赋值函数详解

    赋值函数
            每个类只有一个赋值函数  
            由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。
        1,如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。
                   以类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被释放了两次。   
            2,拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋值函数吗?  
               String a(“hello”);   
                 String b(“world”); 
                 String c = a;   // 调用了拷贝构造函数,最好写成 c(a); 
              c = b;      // 调用了赋值函数   
                   本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。   
            类String的拷贝构造函数与赋值函数   
     // 拷贝构造函数            
             String::String(const String &other)   
             {   
                 int length = strlen(other.m_data);  // 允许操作other的私有成员m_data 
                   m_data = new char[length+1];  
                 strcpy(m_data, other.m_data);  
          }   
    // 赋值函数   
          String & String::operator =(const String &other)   
           {  
                    if(this == &other)          // (1) 检查自赋值
                              return *this;   
              delete [] m_data;            // (2) 释放自己原有的内存资源 
                  int length = strlen(other.m_data);     // (3)分配新的内存资源,并复制内容
                m_data = new char[length+1];   
                  strcpy(m_data, other.m_data);   
                
                  return *this;              // (4)返回本对象的引用
       }   
          类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返回的将是垃圾。   偷懒的办法处理拷贝构造函数与赋值函数   如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,怎么办?

  • 相关阅读:
    webpack基础
    LeetCode232. 用栈实现队列做题笔记
    mysql 时间加减一个月
    leetcode 1381. 设计一个支持增量操作的栈 思路与算法
    LeetCode 141. 环形链表 做题笔记
    leetcode 707. 设计链表 做题笔记
    leetcode 876. 链表的中间结点 做题笔记
    leetcode 143. 重排链表 做题笔记
    leetcode 1365. 有多少小于当前数字的数字 做题笔记
    LeetCode1360. 日期之间隔几天 做题笔记
  • 原文地址:https://www.cnblogs.com/chris-cp/p/3907690.html
Copyright © 2011-2022 走看看