• C++ 浅拷贝与深拷贝


    完整程序见C++ 浅拷贝 深拷贝

    • 没有经过重载,"=" 的作用就是把左边的变量变得和右边的相等,即执行逐个字节拷贝的工作,对于指针变量,会使得两个指针指向同一个地方,这样的拷贝就叫做“浅拷贝”。
    • 将一个指针变量指向的内容复制到另一个指针变量指向的地方,这样的拷贝就叫做“深拷贝”。
    class CString
    {
    private:
    	char* str;
    public:
    	CString() :str(NULL) {}
    	~CString() { if (str) delete[] str; }
    	const char* c_str() const { return str; }
    	CString& operator=(const char* s)
    	{
    		char* str_tmp = NULL;
    
    		if (s)
    		{
    			str_tmp = new char[strlen(s) + 1];
    			strcpy(str_tmp, s);
    		}
    		else
    			str_tmp = NULL;
    
    		if (str)
    			delete[] str;
    
    		str = str_tmp;
    
    		return *this;
    	}
    };
    

    按照上面 CString 类的写法,下面的程序片段 "s1 = s2;" 执行的是浅拷贝,会引发问题:

    CString s1, s2;
    s1 = "this";
    s2 = "that";
    s1 = s2;
    

    我们可以看到,浅拷贝将导致一系列问题:

    • 如不定义自己的赋值运算符,那么 "s1 = s2;" ,实际上导致 s1.str 和 s2.str 指向同一地方。这导致 s1.str 原来指向的那片动态分配的存储空间再也不会被释放,变成内存垃圾,即内存泄漏。
    • 此外 s1 和 s2 消亡时都会执行 "delete[] str;" ,这就使得同一片存储空间被释放两次,会导致严重的内存错误,可能会引发程序意外中止。
    • 而且,如果执行完 "s1 = s2;" 后又执行 "s1 = "other";" ,会导致 s2.str指向的地方被 delete 释放。

    为解决上述问题,需要对 "=" 做再次重载。重载后的 "=" 逻辑,应该是使得执行 "s1 = s2;" 后, s1.str 和 s2.str 依然指向不同的地方,但是这两处地方所储存的内容是一样的。再次重载 "=" 的写法如下:

    CString& CString::operator=(const CString& s)		// 深拷贝
    {
    	// 为了应对 s=s 这样的情况。其实这里的自赋值判断是多余的,因为下面的写法可以处理自赋值的情况,同时还是异常安全的。
    	if (this == &s)
    		return *this;
    
    	char* str_tmp = NULL;
    	if (s.str)
    	{
    		str_tmp = new char[strlen(s.str) + 1];
    		strcpy(str_tmp, s.str);
    	}
    	else
    		str_tmp = NULL;
    
    	if (str)
    		delete[] str;
    
    	str = str_tmp;
    
    	return *this;
    }
    

    程序第3行要判断 this == &s ,是因为要应付这样的情况:s1=s1 。这句 "s1=s1" 本不该改变 s1 的内容才对。

    重载了两次的 "=" 的CString类依然可能导致问题,因为没有重写复制构造函数。比如下面的情况:

    CString s21;
    s21 = "Transformers";
    CString s22(s21);
    

    默认复制构造函数执行的是浅拷贝,还会使得 s21.str 和 s22.str 指向同一个地方。因此,还应该为 CString 类编写如下复制构造函数,以完成深拷贝:

    CString::CString(const CString& s)			// 深拷贝
    {
    	if (s.str)
    	{
    		str = new char[strlen(s.str) + 1];
    		strcpy(str, s.str);
    	}
    	else
    		str = NULL;
    }
    
  • 相关阅读:
    MFC和Qt优缺点 (MFC几乎没有优点、全面下风)
    获得WIN7管理员权限(可通过修改注册表,或者组策略改变)
    tolua#是Unity静态绑定lua的一个解决方案
    C#实现拼图游戏
    FastDFS分布式文件系统
    生成动态Lambda表达式1
    Azure IoT
    SignalR
    延迟队列功能
    监控知识体系
  • 原文地址:https://www.cnblogs.com/ltimaginea/p/13997408.html
Copyright © 2020-2023  润新知