C++智能指针的使用
C++11中提供了三种智能指针(unique_ptr、shared_ptr、weak_ptr)来自动回收堆分配的对象。
unique_ptr
unique_ptr如它的名字所传达的意思,其所指向的内存区不能与unique_ptr定义的另一个指针共享。看代码比较容易理解。
#include <memory>
#include <iostream>
using namespce std;
int main(){
unique_ptr<int> p1(new int(11));
unique_ptr<int> p2 = p1; //不能通过编译
}
p1为unique_ptr类型指针,其不能与p2共享同一片内存区域。
当然也可以用标准库的move函数显式的将“所有权”转移给另一个unique_ptr指针,但原来的指针名将不能再使用。
#include <memory>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
unique_ptr<int> p1(new int(11));
unique_ptr<int> p2 = move(p1);//用move函数进行“所有权”转移
cout << *p1 << endl;//能编译通过,但运行时报Segmentation fault错误
cout << *p2 << endl;
p2.reset();//可以显式地进行内存释放。
p2.reset();//多次释放也不会报错
}
可以看到“所有权”已经被转移走的p1已经不能用*来获取存储值了。另外需要注意的一点是,unique_ptr定义的指针可以不用自己来释放内存。但也可以自己显式地用reset释放内存,而且多次释放也不会报错。
shared_ptr
shared_ptr相对于unique_ptr来说最主要的区别是它可以共享指针,可以多个指针变量指向一片共同的存储区。
#include <memory>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
shared_ptr<int> sp1(new int(11));
shared_ptr<int> sp2 = sp1;//可以正常进行赋值
cout << *sp1 << endl;//可以正常输出
cout << *sp2 << endl;//可以正常输出
sp1.reset();
// sp2.reset();
// cout << *sp1 << endl;
cout << *sp2 << endl;
}
可以看到上面虽然用reset显式地释放了sp1指向的内存。但实际上并没有真正释放其指向的内存。因为sp2依然可以正常访问。可以想象,共享指针内部实现了一个计数,只有指向该内存空间的所有共享指针都进行了释放操作,该内存才真正释放。这避免了普通指针进行多次释放引发的错误。
weak_ptr
weak_ptr可以指向shared_ptr指针指向的对象内存,但并不拥有该内存。使用weak_ptr的lock成员函数可返回其指向内存的一个shared_ptr对象,且在所指对象已经无效时,返回指针空值(nullptr)。这在验证share_ptr智能指针的有效性上会很有作用。
#include <iostream>
#include <memory>
using namespace std;
void Check(weak_ptr<int> & wp)
{
shared_ptr<int> sp = wp.lock(); //转换为shared_ptr<int>
if(sp != nullptr)
{
cout << "still " << *sp << endl;
}
else
{
cout << "pointer is invalid." << endl;
}
}
int main(int argc, char** argv)
{
shared_ptr<int> sp1(new int(22));
shared_ptr<int> sp2 = sp1;
weak_ptr<int> wp = sp1;//指向shared_ptr<int>所指的对象
cout << *sp1 << endl;
cout << *sp2 << endl;
Check(wp); //still 22
sp1.reset();
cout << *sp2 << endl;
Check(wp); //still 22
sp2.reset();
Check(wp);//pointer is invalid.
}
当对sp1和sp2都调用了reset函数。这样导致对唯一的堆内存对象的引用计数降至0。一旦引用计数变成0后,shared_ptr<int>就会释放堆内存空间,指针就会失效。此时再调用weak_ptr的lock函数时就会返回一个指针空值nullptr。而Check函数则会打印pointer is invalid.
关注公众号《首飞》回复“机器人”获取精心推荐的C/C++,Python,Docker,Qt,ROS1/2,机器人学等机器人行业常用技术资料。