MyString(智能指针与深拷贝浅拷贝)

一、智能指针

class my_unique_ptr
{
private:
	Int* ptr;
public:
	my_unique_ptr(Int *p=nullptr):ptr(p){}
	~my_unique_ptr()
	{
		delete ptr;
		ptr = nullptr;
	}
	
	Int* get() const//返回ptr的值
	{
		return ptr;
	}
	Int &operator*()const { return *get(); }
	Int *operator->()const { return get(); }
};
void func(int x)
{
	my_unique_ptr ip(new Int(x));
	ip->SetValue(20);
	cout << (*ip).GetValue() << endl;
}
int main()
{
	func(10);
	return 0;
}

首先进入主函数会给主函数分配一个栈,然后向下执行到func函数,会给func函数分配一个栈,然后给形参x分配一个空间,x的值为10,然后我们定义了一个ip对象(这里的ip不是指针,看清楚),然后给ip分配一个空间,对象ip中会有一个成员ptr,然后我们进入Int的构造函数(首先从堆区申请一个空间来构建Int对象,并初始化为10,然后把地址给ip中的ptr指针),这是ptr指向Int对象。

然后我们 调动->的重载

ip.operator->()

调动这个函数相当于将ip中的ptr指针返回(ip.ptr)然后我们再进行指向,指向SetValue()函数。

这里->调动两次,一次返回ptr,一次调动ptr对象中的SetValue()方法。

相当于

ip.operator()->SetValue(20);
Int &operator*()const { return *get(); 

这个返回的是ptr所指之物(Int),然后用此调动Int的成员方法,相当于

operator*(&ip).GetValue();

但是相比于普通的指针可以申请double类型,int类型的指针,我们的智能指针还是有缺陷的,我们只能创建我们设定好的Int对象的智能指针,用 函数模板可以解决这个问题。

template<class T>
class my_unique_ptr
{
private:
	T* ptr;
public:
	my_unique_ptr(T *p=nullptr):ptr(p){}
	~my_unique_ptr()
	{
		delete ptr;
		ptr = nullptr;
	}
	
	T *get() const//返回ptr的值
	{
		return ptr;
	}
	T &operator*()const { return *get(); }
	T *operator->()const { return ptr; }
	operator bool()const { return ptr != nullptr; }
	void reset(T* p = nullptr)
	{
		delete ptr;
		ptr = p;
	}
};
void func(int x)
{
	my_unique_ptr<Int> ip(new Int(x));
	ip->SetValue(20);
	cout << (*ip).GetValue() << endl;
}
int main()
{
	my_unique_ptr<int> ap(new int(10));
	my_unique_ptr<double> dp(new double(12.23));
	cout << *ap << endl;
	cout << *dp<< endl;
	my_unique_ptr<Int> cp(new Int(10));
	cout << *cp << endl;

}

二、深拷贝和浅拷贝问题

下面这个程序会出现什么问题?

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class MyString
{
private:
	char* ptr;
public:
	MyString(const char* str = nullptr)
	{
		if (str != nullptr)
		{
			int len = strlen(str);
			ptr = new char[len + 1];
			strcpy(ptr, str);
		}
		else
		{
			ptr = new char[1];
			*ptr = '\0';
		}
	}
	~MyString()
	{
		if (ptr != nullptr)
		{
			delete[]ptr;
		}
		ptr = nullptr;
	}
	void PrintString()
	{
		if (ptr != nullptr)
		{
			cout << ptr << endl;
		}
	}
};

int main()
{
	MyString s1("yhpinghello");
	s1.PrintString();
	MyString s2(s1);
	s2.PrintString();
	return 0;
}

在创建s2的时候,因为我们没有编写拷贝构造函数,所以只是会进行简单的按位拷贝,s2中的ptr指针会指向s1指向堆区内容的首地址,然后执行正常,一直到return 0的时候,开始先进行s2的析构,会将ptr指针置为空,释放s2所指空间,但是s1此时还在指向这个空间,他变成了悬空指针,当我们再要去析构s1的时候,就会对同一个空间析构两次,这就会让系统崩溃。

这就是我们所说的浅构造:

MyString(const MyString &st):ptr(st.ptr){}

只是简单的 将值赋值 

const char *p="abcdefg";
sizeof(p);//4
strlen(p);//7

一个是类型的大小,一个是字符串的长度。

深拷贝:
对指针所指之物在堆区进行开空间赋值。

MyString(const MyString& st)
	{
		if (st.ptr != nullptr)
		{
			int len = strlen(st.ptr);
			ptr = new char[len + 1];
			strcpy(ptr, st.ptr);
		}
		else
		{
			ptr = nullptr;
		}
	}

还有这个重载赋值运算符的例子:

我们该怎么样把它变成深拷贝呢?

MyString& operator=(const MyString& it)
	{
		if (this == &it)
			return *this;
		delete[]this->ptr;
		this->ptr = nullptr;
		if (it.ptr != nullptr)
		{
			int len = strlen(it.ptr);
			ptr = new char[len + 1];
			strcpy(ptr, it.ptr);
		}
		return *this;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值