5.3 弱指针
弱指针(weak_ptr) 是用来同共享指针(shared_ptr) 配合使用的智能指针,它不参与引用计数,目的是避免形成指针环链。
我们先来看一个使用共享指针导致形成指针环链,最终被管理对象无法释放的例子。
// filename: ptr_circle.cpp
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Point {
public:
Point(float ax=0, float ay=0):x(ax), y(ay) {
cout << "Point(" << x << "," << y << ")\n";
}
~Point() {
cout << "~Point(" << x << "," << y << ")\n";
}
// 定义为虚函数
void info(void) {
cout << "点(" << x << "," << y << ")\n";
}
public:
// 使用共享指针指向下一个点
shared_ptr<Point> next_point; // 指向图形的下一个点
public:
float x;
float y;
};
vector<shared_ptr<Point>> get_triangle() {
vector<shared_ptr<Point>> points;
shared_ptr<Point> ptr1(new Point(0.0, 1.0)); // 引用计数为1
shared_ptr<Point> ptr2(new Point(1.0, 0.0)); // 引用计数为1
shared_ptr<Point> ptr3(new Point(1.0, 1.0)); // 引用计数为1
ptr1->next_point = ptr2; // 共享指针引用计数变为2
ptr2->next_point = ptr3;
ptr3->next_point = ptr1;
points.push_back(ptr1);
points.push_back(ptr2);
points.push_back(ptr3);
return points;
}
int main(int argc, char * argv[]) {
std::cout << "-- 进入 main 函数 --" << std::endl;
{
std::cout << "- 进入内部作用域 -" << std::endl;
vector<shared_ptr<Point>> ptr_shape = get_triangle();
cout << "- 即将离开内部作用域 -" << endl;
}
// 此时所有的 被管理的对象的引用计数为 1,被管理对象不会被释放
cout << "-- 已离开内部作用域 --" << endl;
return 0;
}
编译和运行结果如下:
weimz@mzstudio:~/old$ g++ -o ptr_circle ptr_circle.cpp
weimz@mzstudio:~/old$ ./ptr_circle
-- 进入 main 函数 --
- 进入内部作用域 -
Point(0,1)
Point(1,0)
Point(1,1)
- 即将离开内部作用域 -
-- 已离开内部作用域 --
可见上述 Point 类虽然使用了共享指针,但 Point 类创建的三个对象形成了环链。对象没有释放。内存丢失。解决这一问题的方式是对可能形成环链的对象使用弱指针,避免增加引用计数。即上述 Point类的的成员变量 next_point 使用弱指针可以解决这一问题。
语法
// 创建弱指针并直接管理单个对象
std::weak_ptr<类> ptr(对象);
// 创建空弱指针
std::weak_ptr<类> ptr;
常用成员函数
成员函数
说明
reset重新设定管理对象指针。
swap交换两个同类型智能指针管理的对象。
operator =修改弱指针的指向。
use_count返回管理对象的共享指针的引用计数(弱指针没有引用计数)。
operator bool判断是否为空指针。
expired检查引用计数是否已经是
0,即此弱指针已经无效,无效返回 true。lock返回一个共享指针(需要用变量绑定),引用计数增加1,确保对象不会被销毁。
示例
修改 Point 的成员变量 next_point 为 弱指针
// filename: weak_ptr.cpp
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Point {
public:
Point(float ax=0, float ay=0):x(ax), y(ay) {
cout << "Point(" << x << "," << y << ")\n";
}
~Point() {
cout << "~Point(" << x << "," << y << ")\n";
}
// 定义为虚函数
void info(void) {
cout << "点(" << x << "," << y << ")\n";
}
public:
// 使用弱指针指向下一个点
weak_ptr<Point> next_point; // 指向图形的下一个点
public:
float x;
float y;
};
vector<shared_ptr<Point>> get_triangle() {
vector<shared_ptr<Point>> points;
shared_ptr<Point> ptr1(new Point(0.0, 1.0)); // 引用计数为1
shared_ptr<Point> ptr2(new Point(1.0, 0.0)); // 引用计数为1
shared_ptr<Point> ptr3(new Point(1.0, 1.0)); // 引用计数为1
ptr1->next_point = ptr2; // 弱指针引用计数不变
ptr2->next_point = ptr3;
ptr3->next_point = ptr1;
points.push_back(ptr1);
points.push_back(ptr2);
points.push_back(ptr3);
return points;
}
int main(int argc, char * argv[]) {
std::cout << "-- 进入 main 函数 --" << std::endl;
{
std::cout << "- 进入内部作用域 -" << std::endl;
vector<shared_ptr<Point>> ptr_shape = get_triangle();
cout << "- 即将离开内部作用域 -" << endl;
}
// 此时所有的 被管理的对象的引用计数为 1,被管理对象不会被释放
cout << "-- 已离开内部作用域 --" << endl;
return 0;
}
编译和运行结果如下:
weimz@mzstudio:~/old$ g++ -o weak_ptr weak_ptr.cpp
weimz@mzstudio:~/old$ ./weak_ptr
-- 进入 main 函数 --
- 进入内部作用域 -
Point(0,1)
Point(1,0)
Point(1,1)
- 即将离开内部作用域 -
~Point(0,1)
~Point(1,0)
~Point(1,1)
-- 已离开内部作用域 --
可见弱指针没有对管理对象的引用计数做加一操作,致使共享指针已经可以将引用计数减为零,达到成功释放被管理对象的目的。