网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
cout<<"test shared\_ptr and new:"<<endl;
//shared\_ptr<int> p4(new int(1024));
shared_ptr<int> p5 = new int(1024); // wrong, no implicit constructor
cout<<\*p4<<endl;
但是,不能将一个new表达式返回的指针赋值给shared_ptr。
另外,特别需要注意的是,不要混用new和shared_ptr!
void process(shared_ptr<int> ptr)
{
cout<<"in process use\_count:"<<ptr.use\_count()<<endl;
}
cout<<"don't mix shared\_ptr and normal pointer:"<<endl;
shared_ptr<int> p5(new int(1024));
process(p5);
int v5 = \*p5;
cout<<"v5: "<<v5<<endl;
int \*p6 = new int(1024);
process(shared_ptr<int>(p6));
int v6 = \*p6;
cout<<"v6: "<<v6<<endl;
可以看到,第二次process p6时,shared_ptr的引用计数为1,当离开process的作用域时,会释放对应的内存,此时p6成为了悬挂指针。
所以,一旦将一个new表达式返回的指针交由shared_ptr管理之后,就不要再通过普通指针访问这块内存!
shared_ptr.reset
shared_ptr可以通过reset方法重置指向另一个对象,此时原对象的引用计数减一。
shared_ptr<int> p1 = make_shared<int>(42);
cout << *p1 << " "<<endl;
auto p2 = p1;
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<endl;
p1.reset(new int(404));
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<endl;
shared_ptr deleter
可以定制一个deleter函数,用于在shared_ptr释放对象时调用。
cout<<"test shared\_ptr deleter:"<<endl;
int \*p7 = new int(1024);
shared_ptr<int> p8(p7, print_at_delete);
p8 = make_shared<int>(1025);
cout << \*p8 <<endl;
unique_ptr基本用法
这块知识可以参考《C++Primer》中文第五版P418
unique_ptr对于所指向的对象,正如其名字所示,是独占的。所以,不可以对unique_ptr进行拷贝、赋值等操作,但是可以通过release函数和reset函数在unique_ptr之间转移控制权。
cout<<"test unique\_ptr base usage:"<<endl;
unique_ptr<int> up1(new int(1024));
cout<<"up1: "<<\*up1<<endl;
unique_ptr<int> up2(up1.release());
cout<<"up2: "<<\*up2<<endl;
//unique\_ptr<int> up3(up1); // wrong, unique\_ptr 不支持拷贝
//up2 = up1; // wrong, unique\_ptr 不支持赋值
unique_ptr<int> up4(new int(1025));
up4.reset(up2.release());
cout<<"up4: "<<\*up4<<endl;
release()返回的指针通常用来初始化另一个智能指针或给另外一个智能指针赋值。
unique_ptr作为参数和返回值
上述对于拷贝的限制,有两个特殊情况,即unique_ptr可以作为函数的返回值和参数使用,这时虽然也有隐含的拷贝存在,但是并非不可行的。
unique_ptr<int> clone(int p)
{
//正确:从int\*创建一个unique\_ptr<int>
return unique_ptr<int>(new int(p));
}
void process\_unique\_ptr(unique_ptr<int> up)
{
cout<<"process unique ptr: "<<\*up<<endl;
}
cout<<"test unique\_ptr parameter and return value:"<<endl;
auto up5 = clone(1024);
cout<<"up5: "<<\*up5<<endl;
process\_unique\_ptr(move(up5));//
//cout<<"up5 after process: "<<\*up5<<endl; // would cause segmentfault
这里的clone(),编译器知道要返回的对象将要被销毁,因此执行一种特殊的“拷贝”。
unique智能指针的所有权问题需要使用std::move进行转移。
早期标准库使用的是auto_ptr,它具有unique_ptr的部分特性,但不是全部。特别是我们不能再容器内保存auto_ptr,也不能从函数返回auto_ptr。一般推荐使用unique_ptr。
unique_ptr deleter
unique_ptr同样可以设置deleter,和shared_ptr不同的是,它需要在模板参数中指定deleter的类型。好在我们有decltype这个利器,不然写起来好麻烦。
cout<<"test unique_ptr deleter:"<<endl;
int *p9 = new int(1024);
unique_ptr<int, decltype(print_at_delete) *> up6(p9, print_at_delete);
unique_ptr<int> up7(new int(1025));
up6.reset(up7.release());
weak_ptr
weak_ptr一般和shared_ptr配合使用。它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。这样就有可能出现weak_ptr所指向的对象实际上已经被释放了的情况。因此,weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。
cout<<"test weak\_ptr basic usage:"<<endl;
auto p10 = make_shared<int>(1024);
weak_ptr<int> wp1(p10);
cout<<"p10 use\_count: "<<p10.use\_count()<<endl;
shared_ptr<int> p11 = wp1.lock();
if(p11)
{
cout<<"wp1: "<<\*p11<<" use count: "<<p11.use\_count()<<endl;
}
else
{
cout << "p11 is empty"<<endl;
}
p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj
p11.reset(new int(1026));
shared_ptr<int> p12 = wp1.lock();
if(p12)
{
cout<<"wp1: "<<\*p12<<" use count: "<<p12.use\_count()<<endl;
}
else
{
cout << "p12 is empty"<<endl;
}
if (!wp1.expired()){//等价于p12 != nullptr
cout<<"shared\_ptr ok\n"<<endl;
cout<<"wp1: "<<\*p12<<" use count: "<<p12.use\_count()<<endl;
}
else
{
cout << "p12 is empty"<<endl;
}
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
56469)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新