博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
拷贝构造函数与赋值操作符的具体实现 【转】参考度4.5星
阅读量:6547 次
发布时间:2019-06-24

本文共 2550 字,大约阅读时间需要 8 分钟。

源地址:

PS: 主要看string的定义以及浅拷贝危害

------------------------------------------------------------------------

对含有指针成员变量的类来说,使用默认的拷贝构造赋值操作是不安全的,具体的原因是默认的函数都属于浅拷贝,所谓浅拷贝就是指只对指针本身进行拷贝操作而对于指针所指向的内容不进行任何操作,这显然至少会带来2个问题,第一个是内存泄漏,因为指针本身被一个新值所覆盖,造成指针原先指向的内存将无法得到释放的机会。另一个问题就是重复引用问题,两个(或者更多)的指针指向同一块内存,当对其中一个指针进行delete操作后,所有对其他指向这块已经被释放的内存的指针的操作,结果都是无法预测的。同样,当修改其中一个对象的指针成员所指向内存中的数据时,其它对象会跟着一起被改变,这显然是错误的。

对于拷贝构造来说,不存在内存泄漏的问题,因为一般对象被创建的时候指针成员都还没有被分配内存,但是存在重复引用的问题。

所以为了避免这些问题,必须显式的定义这两个函数。

本文主要讨论这两个函数的实现。。

1. 拷贝构造函数

假定有以下类型

struct CTREE_NODE_TAG

 {

          TYPE                      data;         

          int                            parent;         

          CList<int, int&>     child;

}

由于存在CList类型成员child, 所以须实现拷贝构造以及赋值操作符函数;

 CTREE_NODE_TAG(const CTREE_NODE_TAG& rhs)

  :data(rhs.data), parent(rhs.parent)

  {
//   child.RemoveAll();
   int* pNode;
   POSITION positionRhs = rhs.child.GetHeadPosition();
   POSITION positionTarget = child.GetHeadPosition();
   while(positionRhs!=NULL)
   {
    if(positionTarget == NULL)//只有当目标对象长度小于拷贝对象时才创建新的结点;注:这里可以不需要,应为初始化时child的长度为0
    {
     pNode = new(int);
     *pNode = rhs.child.GetNext(positionRhs);
     child.AddTail(*pNode);
    }
    else//
    {
     *pNode = rhs.child.GetNext(positionRhs);
     child.SetAt(positionTarget, *pNode);
     child.GetNext(positionTarget);
    }

   } 

   while(positionTarget != NULL)//Free the extra element 注:这里可以不需要,应为初始化时child的长度为0
   {
    child.RemoveAt(positionTarget);
    child.GetNext(positionTarget);
   }
  }

对于非指针类型跟默认实现一样直接复制就可以了,对于指针类型的成员变量,则需要对指针所指向的内容进行复制,而不是简单的对指针本身进行复制;

注意:  当增加了新的成员变量时,不要忘了更新拷贝构造函数;

2.    赋值操作符

对于赋值操作符基本上跟拷贝构造类似,但需要注意以下几点:

1) 防止内存泄漏: 对于指针型成员变量动态分配内存的)要先释放内存

2) 对于有基类的情况必须显式的调用基类的的赋值操作;

 

class String{  public:  ~ String(void); // 析构函数  String(const char* str = NULL);//普通构造函数  String(const String &other);//拷贝构造函数  String &operate = (const String &other);//赋值操作  private:  char * m_data;   }// String 的析构函数  String::~String(void)   {    delete [] m_data;  }   // String 的普通构造函数   String::String(const char *str)  {    if(str==NULL)    {    m_data = new char[1];     *m_data = ‘\0’;     }    else   {    int length = strlen(str);     m_data = new char[length+1];    strcpy(m_data, str);    }  }   // 拷贝构造函数  String::String(const String &other)   {     int length = strlen(other.m_data);    m_data = new char[length+1];     strcpy(m_data, other.m_data);   }  // 赋值函数  String & String::operate =(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;   }

转载于:https://www.cnblogs.com/nkxyf/archive/2012/07/18/2598048.html

你可能感兴趣的文章
jQuery 插件-(初体验一)
查看>>
PHP语言 -- Ajax 登录处理
查看>>
基于js的CC攻击实现与防御
查看>>
我的家庭私有云计划-19
查看>>
项目实践中Linux集群的总结和思考
查看>>
关于使用Android NDK编译ffmpeg
查看>>
监控MySQL主从同步是否异常并报警企业案例模拟
查看>>
zabbix从2.2.3升级到最新稳定版3.2.1
查看>>
我有一个网站,想提高点权重
查看>>
浅谈(SQL Server)数据库中系统表的作用
查看>>
微软邮件系统Exchange 2013系列(七)创建发送连接器
查看>>
程序员杂记系列
查看>>
【树莓派】制作树莓派所使用的img镜像(一)
查看>>
理解网站并发量
查看>>
spring整合elasticsearch之环境搭建
查看>>
TensorFlow 架构与设计-编程模型【转】
查看>>
如何运行Struts2官网最新Demo?
查看>>
'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)
查看>>
XDebug 教程
查看>>
js 去html 标签
查看>>