【C++】 enable_shared_from_this 用法
enable_shared_from_this 用法
enable_shared_from_this 是 C++ 标准库中的一个模板类,用于在类的成员函数内部安全地获取指向自身的 shared_ptr。为什么需要它?直接用 this 构造 shared_ptr 会导致双重释放:
class Foo {
public:
std::shared_ptr<Foo> get() {
return std::shared_ptr<Foo>(this); // ❌ 危险!产生第二个独立的引用计数
}
};
auto p1 = std::make_shared<Foo>();
auto p2 = p1->get(); // p1 和 p2 各自独立管理同一块内存 → 析构时 double free
正确用法:
#include <memory>
class Foo : public std::enable_shared_from_this<Foo> {
public:
std::shared_ptr<Foo> get() {
return shared_from_this(); // ✅ 共享同一个引用计数
}
};
auto p1 = std::make_shared<Foo>();
auto p2 = p1->get();
std::cout << p1.use_count(); // 2,引用计数正确共享
例子 1:HTTP Session(❌ 错误 vs ✅ 正确)
❌ 错误版本:对象提前析构,回调访问悬空指针
#include <iostream>
#include <memory>
#include <functional>
#include <thread>
#include <chrono>
// 模拟异步操作(比如网络库)
void async_read(std::function<void(std::string)> callback) {
std::thread([cb = std::move(callback)]() {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟 IO 延迟
cb("received data");
}).detach();
}
class Session {
public:
Session(int id) : id_(id) {
std::cout << "[Session " << id_ << "] 构造\n";
}
~Session() {
std::cout << "[Session " << id_ << "] 析构 ← 对象已销毁!\n";
}
void start() {
// ❌ 直接捕获 this 裸指针
async_read([this](std::string data) {
// 100ms 后执行这里,但 Session 可能已经析构了!
std::cout << "[Session " << id_ << "] 收到: " << data << "\n"; // 💥 UB!
});
}
private:
int id_;
};
int main() {
{
auto session = std::make_shared<Session>(1);
session->start();
} // ← shared_ptr 离开作用域,Session 立刻析构
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// 回调在这里执行,但 Session 已经没了 → 未定义行为
}
✅ 正确版本:shared_from_this 延长生命周期
#include <iostream>
#include <memory>
#include <functional>
#include <thread>
#include <chrono>
void async_read(std::function<void(std::string)> callback) {
std::thread([cb = std::move(callback)]() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
cb("received data");
}).detach();
}
class Session : public std::enable_shared_from_this<Session> {
public:
Session(int id) : id_(id) {
std::cout << "[Session " << id_ << "] 构造\n";
}
~Session() {
std::cout << "[Session " << id_ << "] 析构\n";
}
void start() {
// ✅ 捕获 shared_ptr,引用计数 +1,对象至少活到回调结束
auto self = shared_from_this();
async_read([self](std::string data) {
std::cout << "[Session " << self->id_ << "] 收到: " << data << "\n"; // ✅ 安全
});
std::cout << "[Session " << id_ << "] start() 结束, use_count="
<< self.use_count() << "\n"; // 此时 = 3(main里1个 + self + lambda捕获1个)
}
private:
int id_;
};
int main() {
{
auto session = std::make_shared<Session>(1);
session->start();
// start() 返回后,main 的 shared_ptr 是 use_count=2(lambda 里还有一个 self)
} // ← main 的 shared_ptr 析构,use_count 变为 1,对象还活着!
std::cout << "main: shared_ptr 已离开作用域,等待回调...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// 回调执行完毕,lambda 销毁,self 析构,use_count=0,Session 才真正析构
}
例子 2:链式异步操作(连续多个回调)
这个场景更真实:一个对象需要连续发起多个异步操作(读 → 处理 → 写),每一步都需要保证对象存活。
❌ 错误版本:用 new + 裸指针,生命周期完全失控
class Pipeline {
public:
void run() {
// 第一步:异步读
async_step1([this]() { // ❌ 裸 this
process();
async_step2([this]() { // ❌ 裸 this,此时 this 可能已经没了
write_result();
});
});
}
void process() { /* ... */ }
void write_result() { /* ... */ } // 💥 可能访问已析构对象
};
// 调用方根本不知道对象何时能被安全删除
Pipeline* p = new Pipeline();
p->run();
delete p; // ❌ 可能太早删了,也可能永远不删(内存泄漏)
✅ 正确版本:每一步都续命
#include <iostream>
#include <memory>
#include <functional>
#include <thread>
#include <chrono>
// 模拟三个异步步骤
void async_step(int delay_ms, std::function<void()> cb) {
std::thread([=]() {
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
cb();
}).detach();
}
class Pipeline : public std::enable_shared_from_this<Pipeline> {
public:
static std::shared_ptr<Pipeline> create(std::string name) {
return std::shared_ptr<Pipeline>(new Pipeline(std::move(name)));
// 注意:不能用 make_shared,因为构造函数是私有的
}
void run() {
std::cout << name_ << " 开始运行, use_count=" << shared_from_this().use_count() << "\n";
step1();
}
private:
explicit Pipeline(std::string name) : name_(std::move(name)) {}
void step1() {
auto self = shared_from_this(); // 引用计数 +1
std::cout << name_ << " step1 发起, use_count=" << self.use_count() << "\n";
async_step(50, [self]() {
// ✅ self 保证 Pipeline 在这里仍然存活
std::cout << self->name_ << " step1 完成\n";
self->step2(); // 进入下一步
});
} // self 在 lambda 里,step1() 返回后对象不会析构
void step2() {
auto self = shared_from_this(); // 再次续命
std::cout << name_ << " step2 发起, use_count=" << self.use_count() << "\n";
async_step(50, [self]() {
std::cout << self->name_ << " step2 完成\n";
self->step3();
});
}
void step3() {
auto self = shared_from_this();
std::cout << name_ << " step3 发起, use_count=" << self.use_count() << "\n";
async_step(50, [self]() {
std::cout << self->name_ << " step3 完成,Pipeline 结束\n";
// lambda 销毁 → self 析构 → use_count=0 → Pipeline 析构
});
}
std::string name_;
};
int main() {
{
auto p = Pipeline::create("MyPipeline");
p->run();
} // ← main 的 shared_ptr 析构,但 Pipeline 仍然活着(被各步骤的 self 持有)
std::cout << "main: 已离开作用域,Pipeline 在后台继续运行...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
输出:
MyPipeline 开始运行, use_count=2
MyPipeline step1 发起, use_count=3
main: 已离开作用域,Pipeline 在后台继续运行...
MyPipeline step1 完成
MyPipeline step2 发起, use_count=2
MyPipeline step2 完成
MyPipeline step3 发起, use_count=2
MyPipeline step3 完成,Pipeline 结束
[Pipeline 析构] ← 最后一个 self 销毁后才析构

浙公网安备 33010602011771号