智能指针是什么?
C++11中有shared_ptr与weak_ptr、unique_ptr等智能指针(smart pointer),定义在
<memory>
中。可以对动态资源进行管理,保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。
shared_ptr
介绍
shared_ptr允许多个该智能指针“同时管理/拥有”同一堆分配对象的内存,这通过引用计数实现,会记录有多少个shared_ptr共同指向一个对象,一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。
通俗的来讲,比如放学之后,教室的灯没有具体的管理者,我们会让最后一个走的人关灯,这就是shared_ptr的一个通俗解释。
一些使用场景
- 对象之间“共享数据”,对象创建与销毁“分离”。
- 放入容器中的动态对象,C++STL的容器在其生命周期结束的时候会调用该类的析构函数,也就是对容器中的每一个对象都调用对应的析构函数,此时shared_ptr的计数变量会不断减一,直到减为零的时候会删除该智能指针指向的对象。
int main() {
shared_ptr<int> sptr1(new int(123));
shared_ptr<int> sptr2 = sptr1;
cout << "count: " << sptr2.use_count() << '\n'; //2
sptr1.reset(); //引用计数减1(重置该智能指针的指向)
cout << "count: " << sptr2.use_count() << '\n'; //1
return 0;
}
可能会出现的问题
当shared_ptr出现循环引用的时候,会出现内存泄漏,两个shared_ptr循环引用的时候会使这两个shared_ptr的计数变量都不会清零,所以不会调用指向对象的析构函数,导致内存泄漏,解决方法:weak_ptr。
weak_ptr
介绍
weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用计数的增加或减少。
weak_ptr的使用更为复杂一点,它可以指向shared_ptr指针指向的对象内存,却并不拥有该内存,而使用weak_ptr成员lock,则可返回其指向内存的一个share_ptr对象,且在所指对象内存已经无效时,返回指针空值nullptr。
shared_ptr会共享对象的所有权,但是有一些场景如果有一个像shared_ptr但是又不参与资源所有权共享的指针是很方便的。换句话说,是一个类似shared_ptr但不影响对象引用计数的指针。不参与资源所有权就意味着不会对资源的生命周期产生影响,有利于对象之间解除关系。
一些使用场景
For example A和B相互加了好友,假设我们用一个指针来指向自己的好友,如果是shared_ptr,那么A和B的生命周期是相互影响的,而实际上我们并不希望这种强绑定,假设B注销了账户,A根本不用知道,只有当A想发消息给B的时候系统才会发出提示:你还不是该用户的朋友。这时,我们就需要使用weak_ptr(当你想使用对象,但是并不想管理对象,并且在需要使用对象时可以判断对象是否还存在)。
int main() {
shared_ptr<int> sptr1(new int(123));
shared_ptr<int> sptr2 = sptr1;
weak_ptr<int> wptr = sptr1; // 指向shared_ptr<int> sptr1所指向的对象
cout << "count: " << wptr.use_count() << '\n'; // 2
sptr1.reset();
cout << "count: " << wptr.use_count() << '\n'; // 1
sptr2.reset();
cout << "count: " << wptr.use_count() << '\n'; // 0
return 0;
}
unique_ptr
介绍
unique_ptr持有对对象的独有权,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义(move)来实现)。
unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。
离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。
int main() {
unique_ptr<int> uptr1(new int(123));
//unique_ptr<int> uptr2 = uptr1; // 不能通过编译,同时只能有一个unique_ptr指向同一对象
unique_ptr<int> uptr3 = move(uptr1); // 使用移动语义,现在uptr3是数据的唯一的unique_ptr
uptr3.reset(); // 释放内存
uptr1.reset(); // 不会导致运行时错误
uptr4.reset(new int(1234)); //"绑定"动态对象
uptr4 = nullptr; //显式销毁所指对象,同时智能指针变为空指针。与up4.reset()等价
unique_ptr<int> uptr5(new int(12345));
int *p = uptr5.release(); //只是释放控制权,不会释放内存,返回之前管理内存的地址
delete p; //释放堆区资源
return 0;
}
auto_ptr
C++17中被删除。不做过多解释~