String类的深浅拷贝以及写时拷贝

文章探讨了C++中对象拷贝的两种方式——浅拷贝和深拷贝,以及它们在内存管理和防止二次释放问题上的作用。浅拷贝可能导致多个对象共享同一块内存,而深拷贝则为每个对象创建独立的内存副本。文章通过示例代码展示了如何实现这两种拷贝,并指出在需要修改对象数据时应使用深拷贝。此外,还介绍了使用写时拷贝策略来优化内存使用的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       浅拷贝:类的所有对象的成员变量指针指向同一块空间(成员变量是开辟在堆区的),类默认的拷贝构造函数和赋值运算符重载都采用浅拷贝,如果不加以处理,当析构函数对空间进行释放时,就会出现堆区空间二次释放的问题。但是浅拷贝也可以起到节省内存空间的作用,这里就需要利用静态的成员变量来进行对象计数,析构函数中 对计数进行判断,如果只剩下一个对象再进行真正的析构操作。

       深拷贝:对于拷贝构造和赋值运算符重载重新实现,赋值时每次都要开辟新空间。注意赋值运算符重载中,需要进行旧空间释放(不然会造成内存泄漏)和是否是自身赋值的判断。

      所有对象都只是访问数据而不修改,浅拷贝是可以的,但是当有对象要进行数据修改时就应该按深拷贝来实现。深拷贝和浅拷贝(对象计数)的实现:这种所有的对象都进行统一引用计数的方式是错误的,比如s3应当和s1、s2没有关联,而且这里的成员变量一改俱改。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vld.h>
using namespace std;

class String
{
	friend ostream& operator<<(ostream& cout, const String& s);


public:
	String(const char* str="")
	{
		this->m_data = new char[strlen(str) + 1];
		strcpy(m_data, str);
		this->m_count++;
	}

	String(const String& s)
	{
	/*	this->m_data = new char[strlen(s.m_data)+1];
		strcpy(this->m_data, s.m_data);*/
		this->m_data = s.m_data;
		this->m_count++;
	}

	String& operator=(const String& s)
	{
		if (this != &s)
		{
			this->m_data = s.m_data;
			/*delete this->m_data;
			this->m_data = new char[strlen(s.m_data) + 1];
			strcpy(this->m_data, s.m_data);*/
			this->m_count++;
		}
		return *this;
	}

	~String()
	{
		if (--this->m_count == 0)//浅拷贝和浅赋值
		{
			delete[] m_data;
			m_data = nullptr;
		}
	}

public:

	void do_uper(char* p)
	{
		while (*p != '\0')
		{
			if (*p >= 'a' && *p <= 'z')
			{
				*p -= 32;
			}
			p++;
		}
	}

	void to_upper()//写时拷贝,只有在修改对象成员变量时才开辟新空间
	{
		char* p=NULL;

		if (this->m_count > 1)
		{
			char* tmp = new char [strlen(m_data) + 1];
			strcpy(tmp, this->m_data);
			this->m_data = tmp;
			p = tmp;
			this->m_count--;
		}

		else
		{
			 p = this->m_data;
		}

		do_uper(p);
	}

private:
	char* m_data;
	static int m_count;
};
int String::m_count = 0;

ostream& operator<<(ostream& cout, const String& s)
{
	cout << s.m_data << endl;
	return cout;
}

void test01()
{
	String s("abc");
}

void test02()
{
	String s1("abc");
	String s2 = s1;
	String s3;
	s3 = s1;
	cout << s1;
	cout << s2;
	cout << s3;
}

void test03()
{
	String s1("abc");
	String s2 = s1;
	String s3("xyz");
	s1.to_upper();
	cout << s1;
	cout << s2;
}

int main()
{
	//test01();
	test03();

	system("pause");
	return 0;
}

String类的写时拷贝:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
#include<vld.h>
using namespace std;

//#define DISPLAY

class String_rep
{
	friend class String;
public:
	String_rep(const char* str = "") :m_count(0)
	{
#ifdef DISPLAY
		cout << "Creat String_Rep Obj" << endl;
#endif
		this->m_data = new char[strlen(str) + 1];
		strcpy(m_data, str);
	}

	String_rep(const String_rep& rep)
	{
		this->m_data = rep.m_data;//浅拷贝
		//increament();
	}

	String_rep& operator=(const String_rep& rep)
	{
		if (this != &rep)
		{
		this->m_data = rep.m_data;
		//increament();
		}
	   return *this;
	}

	char* getData()
	{
		return m_data;
	}

	~String_rep()
	{
#ifdef DISPLAY
		cout << "Free String_Rep Obj" << endl;
#endif
		delete[] this->m_data;
		this->m_data = NULL;
	}

	void increament()
	{
		this->m_count++;
	}

	void decreament()
	{
		if (--m_count == 0)
		{
			delete this;//自杀式释放
		}
	}

private:
	char* m_data;
	int m_count;
};

class String
{
	friend  ostream& operator<<(ostream& cout, const String& s);

public:
	String(const char* str = "") :pn(new String_rep(str))
	{
#ifdef DISPLAY
		cout << "Creat String Obj" << endl;
#endif
		pn->increament();
	}
	String(const String& s):pn(s.pn)
	{
		pn->increament();
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			pn->decreament();
			pn = s.pn;
			pn->increament();
		}
		return *this;
	}

	void to_upper()
	{
		String_rep* new_pn = new String_rep(pn->m_data);
		pn->decreament();
		pn = new_pn;
		pn->increament();

		char* p = pn->m_data;
		while (*p != '\0')
		{
			if (*p >= 'a' && *p <= 'z')
				*p -= 32;
			p++;
		}
	}

	~String()
	{
#ifdef DISPLAY
		cout << "Free String Obj" << endl;
#endif
		pn->decreament();
	}
private:
	String_rep* pn;
};

ostream& operator<<(ostream& cout, const String& s)
{
	cout << s.pn->getData() << endl;
	return cout;
}

void test01()
{
	String s1("abc");
	//{
	//	String s1 = s;
	//}

	String s2 = s1;
	String s3("xyz");
}

void test02()
{
	String s("abc");
	String s1("xyz");
	String s2 = s1;
	s = s1;
}

void test03()
{
	String s1("abc");
	String s2 = s1;
	String s3 = s2;
	cout <<"s1="<< s1;
	cout <<"s2="<<s2;

	s1.to_upper();
	cout <<"s1="<< s1;
	cout <<"s2="<< s2;
}


int main()
{
	//test01();
	test03();
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值