系列文章目录
文章目录
前言
UE4中实现了自己的智能指针,在C++中原本也有自己的智能指针,本文将对两者的用法进行剖析,最重要的是通过对智能指针的用法理解,最终收获为什么UE4要这要设计智能指针。
一、为什么需要智能指针-如何养好一只猫
这里我们新建一个小猫的类,具体代码如下:
class Cat
{
public:
Cat()
{
cout << "收养了一只猫" << endl;
}
Cat(string name)
{
cout << "收养了一只猫,猫名字是:" << name << endl;
catName = name;
}
~Cat()
{
cout << "送给别人了一只猫,猫名字是:" << catName << endl;
}
string GetName()
{
return catName;
}
void SetName(string myname)
{
catName = myname;
}
private:
string catName;
};
如果我们不使用智能指针,直接使用普通申请内存方式,由开发人员进行申请内存以及释放,这种方式如下:
int main()
{
Cat* p = new Cat("原始的小嘿");
delete p;
}
这时候程序是没有问题的,可以输入如下结果:
收养了一只猫,猫名字是:原始的小嘿
送给别人了一只猫,猫名字是:原始的小嘿
但是如果程序员比较粗心,没有写释放内存的语句,也就是delete p,那么会发生什么呢
收养了一只猫,猫名字是:原始的小嘿
可以看到,如果没有释放内存,那么只会调用类的构造函数,但是析构函数不会被调用,作为一个养猫人,当然希望只是收养而不要把猫送给别人,但是家里如果猫太多也有负担不了的一天,同样作为程序,如果只是构造而没有调用析构函数,会导致内存的泄露,更严重的就是程序的崩溃。
二、通过unique_ptr认识智能指针
1.第一个智能指针程序
从 C++ 11 开始,引入了三种智能指针unique_ptr,shared_ptr,weak_ptr。其实在C++11之前也有智能指针auto_ptr,但是已经被启用了。智能指针的程序特别简单,你只管创建指针,其他的交给智能指针。
int main()
{
unique_ptr<Cat> u_cat_p1(new Cat("独占指针小嘿"));
}
这时候输出如下
收养了一只猫,猫名字是:独占指针小嘿
送给别人了一只猫,猫名字是:独占指针小嘿
可以看到,我们有申请内存的语句,但是没有释放内存的语句,结果依然是释放了内存调用了析构函数。这就是智能指针的魅力。
2.unique_ptr的特性-这就是你一个人的猫
unique_ptr可以用以下几种方式初始化:
int main()
{
unique_ptr<Cat> u_cat_p1;
Cat* p = new Cat("原始赋值给独占指针的小嘿1");
unique_ptr<Cat> u_cat_p2(p);
unique_ptr<Cat> u_cat_p3(new Cat("原始赋值给独占指针的小嘿2"));
}
上述程序运行后得到如下结果
收养了一只猫,猫名字是:原始赋值给独占指针的小嘿1
收养了一只猫,猫名字是:原始赋值给独占指针的小嘿2
送给别人了一只猫,猫名字是:原始赋值给独占指针的小嘿2
送给别人了一只猫,猫名字是:原始赋值给独占指针的小嘿1
如你所愿,虽然整个程序没有delete但是所有资源都在需要释放的时候被释放掉了。下面我们看看这个unique_ptr中的unique是什么意思,光从字面理解,这就是独自的意思,可以理解为,unique_ptr在同一个时段只能管理一个指针,同时被管理的指针也智能由一个unique_ptr来管理。首先我们用下面的代码来试一下:
int main()
{
Cat* p = new Cat("原始赋值给独占指针的小嘿1");
unique_ptr<Cat> u_cat_p1(p);
unique_ptr<Cat> u_cat_p2(p);
}
然后我在vs中运行了一下:程序崩溃了
线程 0x8b88 已退出,返回值为 0 (0x0)。
引发了异常: 读取访问权限冲突。
**_Val** 是 0xFFFFFFFFFFFFFFFF。
所以从上面的运行结果可以看出,unique_ptr是独占的。
3.unique_ptr的释放-我不想养猫了,我想送给别人
那么如果需要释放控制权怎么做呢,就要用到release,请看下面一段代码:
int main()
{
Cat* p = new Cat("原始赋值给独占指针的小嘿1");
unique_ptr<Cat> u_cat_p1(p);
u_cat_p1.release();
cout << "u_cat_p1指针:" << u_cat_p1 << endl;
cout << "程序执行完毕" << endl;
}
u_cat_p1在程序结束之前释放了p指针,那么p指针就需要手动释放资源,而这时没有人接管p指针了,也没有手动释放,所以运行结果如下,这里补充一点unique_ptr重载了<<输出运算符,输出自动为unique_ptr所管理的指针的地址。
收养了一只猫,猫名字是:原始赋值给独占指针的小嘿1
u_cat_p1指针:0000000000000000
程序执行完毕
release就是释放控制权的命令,那如果想释放控制权同时释放资源可以用到reset或者直接将unique_ptr置为空。代码如下:
int main()
{
Cat* p = new Cat("原始赋值给独占指针的小嘿1");
unique_ptr<Cat> u_cat_p1(p);
cout << "u_cat_p1指针:" << u_cat_p1 << endl;
u_cat_p1.reset();
cout << "u_cat_p1指针:" << u_cat_p1 << endl;
unique_ptr<Cat> u_cat_p2(new Cat("原始赋值给独占指针的小嘿2"));
cout << "u_cat_p2指针:" << u_cat_p2 << endl;
u_cat_p2 = nullptr;
cout << "u_cat_p2指针:" << u_cat_p2 << endl;
cout << "程序执行完毕" << endl;
}
收养了一只猫,猫名字是:原始赋值给独占指针的小嘿1
u_cat_p1指针:0000018749FC5F70
送给别人了一只猫,猫名字是:原始赋值给独占指针的小嘿1
u_cat_p1指针:0000000000000000
收养了一只猫,猫名字是:原始赋值给独占指针的小嘿2
u_cat_p2指针:0000018749FC6600
送给别人了一只猫,猫名字是:原始赋值给独占指针的小嘿2
u_cat_p2指针:0000000000000000
程序执行完毕
4.unique_ptr的转移-送给你的猫,你要养好了
如果说unique_ptr同一个时间只能控制一个指针,那么可不可以把指针转移给别人呢,答案是可以的。可以用move传递给别人。具体代码如下:
int main()
{
Cat* p = new Cat("原始赋值给独占指针的小嘿1");
unique_ptr<Cat> u_cat_p1(p);
cout << "u_cat_p1指针:" << u_cat_p1 << endl;
unique_ptr<Cat> u_cat_p2(std::move(u_cat_p1)); //p1管理的动态内存转移到p2,p1可以正常释放,但不再可用
cout << "u_cat_p1指针:" << u_cat_p1 << endl;
cout << "u_cat_p2指针:" << u_cat_p2 << endl;
cout << "程序执行完毕" << endl;
}
你的猫送给别人了,别人会帮你养好的。所以运行结果如下:
收养了一只猫,猫名字是:原始赋值给独占指针的小嘿1
u_cat_p1指针:0000021A5DB87DB0
u_cat_p1指针:0000000000000000
u_cat_p2指针:0000021A5DB87DB0
程序执行完毕
送给别人了一只猫,猫名字是:原始赋值给独占指针的小嘿1
可以看到所有资源都被完美的释放了。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了unique_ptr智能指针的使用,下一篇将学习共享指针最终要达到学习UE智能指针的目的。