一、智能指针
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;
}