先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
正文
直接进行报错处理。
我们也可以猜测出它的实现方式,那就是在拷贝构造和赋值构造的后面加上delete关键字。
template<class T>
class MyUnique
{
private:
T\* _ptr;
public:
MyUnique(T\* ptr)
:\_ptr(ptr)
{}
~MyUnique()
{
if (_ptr != nullptr)
{
cout << "delete: " << _ptr << endl;
delete _ptr;
_ptr = nullptr;
}
}
MyUnique(MyUnique<T>& Ptr) = delete;
MyUnique& operator=(MyUnique<T>& Ptr) = delete;
T& operator\*()
{
return \*_ptr;
}
T\* operator->()
{
return _ptr;
}
};
2.shared_ptr
(1)引用计数器
shared_ptr是使用最多的智能指针,即它可以进行拷贝构造。
- 每一个智能指针类都有一个专门用于记录该智能指针指向的资源的指针个数的计数器。
- 当多了一个智能指针指向该资源,则对所有指向该资源的智能指针的计数器进行++操作,当一个智能指针不再指向该资源的时候·,所有指向该资源的智能指针的计数器进行–操作。
- 当某一个智能指针将其–到0的时候由该智能指针释放该资源。从而解决了不让拷贝的根本问题:防止资源释放多次。
- 同时智能指针有一个use_count函数来返回计数器的值。
shared_ptr<int> sptr1(new int(1));
shared_ptr<int> sptr2(sptr1);
shared_ptr<int> sptr3(sptr2);
cout << sptr1.use\_count() << endl;
cout << sptr2.use\_count() << endl;
cout << sptr2.use\_count() << endl;
cout << "资源释放成功" << endl;
(2)线程安全
涉及到共享,我们不得不将线程安全问题考虑进来,很显然shared_ptr无论是要管理的资源的使用,还是要指向的该资源对应的计数器的加减操作,都不是线程安全的。
- 对于要管理的资源来说,如果多个线程不去使用该资源,是不会产生问题的。因此如果需要使用该资源由于代码量的不同位置,C++为了保证性能,希望用户来自己保证它的线程安全,即由用户自己来加锁解锁。
- 而对于资源计数器来说,只要增加一个智能指针就会++,减少一个就会–,其逻辑明确简单,因此shared_ptr为其加了锁。
template<class T>
class MyShared
{
private:
T\* _ptr;
mutex\* _pmtx;
int\* _pcount;
public:
MyShared(T\* ptr)
:\_ptr(ptr),
\_pmtx(new mutex),
\_pcount(new int(1))
{}
void AddCount()
{
_pmtx->lock();
(\*_pcount)++;
_pmtx->unlock();
}
void DelCount()
{
_pmtx->lock();
bool flag = false;
if (--(\*_pcount) == 0)
{
if (_ptr != nullptr)
{
cout << "delete: " << _ptr << endl;
delete _ptr;
_ptr = nullptr;
}
delete _pcount;//当为0的时候删除计数器
_pcount = nullptr;
flag = true;
}
_pmtx->unlock();
if (flag == true)
{
delete _pmtx;
_pmtx = nullptr;
}
}
MyShared(MyShared<T>& sp)
:\_ptr(sp._ptr),
\_pcount(sp._pcount),
\_pmtx(sp._pmtx)
{
AddCount();
}
MyShared& operator=(MyShared<T>& sp)
{
if (_ptr != sp._ptr)
{
DelCount();//释放管理的旧资源
_ptr = sp._ptr;
_pcount = sp._pcount;
_pmtx = sp._pmtx;
AddCount();//对管理的新资源的计数器进行++
}
return \*this;
}
//获取引用计数
int use\_count()
{
return \*_pcount;
}
T& operator\*()
{
return \*_ptr;
}
T\* operator->()
{
return _ptr;
}
};
(3)删除器
如果不是new出来的对象如何通过智能指针进行管理呢?其实shared_ptr设计了一个删除器来解决这一问题。
template<class T>
struct FreeFunc
{
void operator()(T\* ptr)
{
cout << "free:" << ptr << endl;
free(ptr);
}
};
template<class T>
struct DeleteArrayFunc
{
void operator()(T\* ptr)
{
cout << "delete[]" << ptr << endl;
delete[] ptr;
}
};
此时使用malloc进行初始化的时候就也可以进行清理空间了:
FreeFunc<int> freeFunc;
shared_ptr<int> sp1((int\*)malloc(4), freeFunc);
DeleteArrayFunc<int> deleteArrayFunc;
shared_ptr<int> sp2((int\*)malloc(4), deleteArrayFunc);
3.weak_ptr
(1)shared_ptr中的循环调用问题
循环调用问题在一些特殊的情况下会产生:
1.node1和node2两个智能指针指向两个节点,引用计数变成1,我们不需要手动delete。
2.node1的_next指向node2,node2的_prev指向node1,引用计数变成2。
3.node1和node2析构,引用计数减到1,但是_next还指向下一个节点。但是_prev还指向上一个节点。
4.也就是说_next析构了,node2就释放了。
5.也就是说_prev析构了,node1就释放了。
6.但是_next属于node的成员,node1释放了,_next才会析构,而node1由_prev管理,_prev属于node2成员,所以这就叫循环引用,谁也不会释放。
struct ListNode
{
shared_ptr<ListNode> _next;
shared_ptr<ListNode> _prev;
};
shared_ptr<ListNode> node1(new ListNode);
shared_ptr<ListNode> node2(new ListNode);
node1 ->_next = node2;
node2 -> _prev = node1;
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
[外链图片转存中…(img-hO0cWbDR-1713331549850)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!