【C++】浅拷贝和深拷贝以及怎样实现一个简单的string类!!!


浅拷贝:

在C++里面很多的时候都会用到用一个对象去给另外一个对象赋值,在表面上看到的两个不同的对象只是两个对象的值是相同的而已,其实在内部两个对象的地址其实是一样的。如下图:

string s1 = "abcdef";
string s2 = s1;


这样的代码存在一个很大的问题,那就是在两个对象指向同一个内存的时候,当有一个对象被销毁的时候,那么这一块内存也会被delete,这样这块内存就会被释放,但是另外一个对象还不知道这块内存已经被释放,这样,当这个对象访问或者对象被销毁的时候就会出现错误。而且这种错误还不是一眼就能看出来的。

深拷贝:

浅拷贝会出现多个对象指向同一块内存的现象,那么可以在重载“=”的时候就给每个对象都分配一块属于自己的内存,这样就可以避免出现多个对象释放同一块内存的现象。那么可以这样实现:


这样的确是可以解决释放内存的问题,但是这样很多次的开辟内存就会使内存碎片变得越来越多,这显然也不是解决这个问题的最佳办法。

解决这个问题可以在这个类里面创建一个计数器,计数器用来计算这个内存有多少个对象在使用,当最后只有一个对象在使用这个内存的时候,当这个对象销毁的时候那么这个内存就可以释放了,如果这个计数器统计的使用这个内存的对象不止一个,那么调用析构函数的时候就不释放这个内存,只需将计数器的数字减一个就可以。

实现计数器的方法:

1、static变量:第一次想到的办法就是用一个static变量来计算,static变量是存储在类里面的公共内存里面,这样是可以实现计数器的功能,但是,在开辟一块新内存的时候这个计数器的值也就会被改变,那么计算出来的值也就不是我们所需要的,这个办法也是不可取的。


2、重新定义一个变量来充当计数器,当每次用一个对象来初始化另外一个对象的时候,可以先将这个指针指向所需的内存,然后将之前的内存释放掉。但是这样的话就会很容易出现内存泄漏的问题,这样做显然也是不可取的。


3、可以和new[]开辟内存的方式一样,在开辟的内存的前面对开辟四个字节的空间来存储计数器的值,这样在释放的时候可以一次就将所开辟的内存一次释放完全。这种方法应该是可以实现的。


模拟实现string:

上面的这种将浅拷贝的深拷贝结合起来的方法也被称为引用计数,最简单的引用计数的实例就是模拟实现string。代码如下:

class String
{
public:
	String (char *pstr = "")
	{
		if (NULL == pstr)
		{
			_pstr = new char[5];   //当pstr为空的时候,只需要将\0拷贝进_pstr里面就好
			_pstr += 4;
			GetNum() = 1;
			strcpy(_pstr,'\0');
		}
		else
		{
			_pstr = new char[strlen(pstr)+1+4];    //这里+1是因为strlen函数计算时候不包括\0,。
			_pstr += 4;
			GetNum() = 1;
			strcpy(_pstr,pstr);
		}
	}

	int& GetNum()
	{
		return *(int*)(_pstr-4);
	}

	String (const String &s)
		:_pstr(s._pstr)
	{
		if (this != &s)
		   GetNum()++;
	}

	String& operator=(String &s)
	{
		if (this != &s)
		{
			if (s._pstr&&0 == --s.GetNum())
			{
				delete[] (_pstr-4);
			}
			_pstr = s._pstr;
			GetNum()++;
		}
		return *this;
	}

	~String()
	{
		if (_pstr&&0 == --GetNum())           //只有在指针不为空,和计数器只有一个对象在使用这块空间的时候将这个内存释放
		{
			delete[] (_pstr-4);
		}
	}
private:
	char *_pstr;
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计实现一个动态整型数组Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数和析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1和v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1和v3的所有元素。 设计实现一个动态整型数组Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数和析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1和v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1和v3的所有元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值