在C++多线程环境下,对象的生命周期管理一直是工程实践中的一大挑战。一旦处理不当,极易引发内存泄漏或程序崩溃,给项目稳定性带来巨大隐患。

建议使用C++智能指针管理对象生命周期,避免直接使用裸指针。智能指针能够自动处理内存管理,提高了代码的安全性和可靠性,同时也减少了手动管理内存的负担,提升了程序的健壮性。

典型场景

一个对象需要委派给工作线程(worker thread)来异步执行某项任务。在此期间,关键在于确保该对象在其生命周期内保持有效,避免在工作线程还在访问它的过程中已经析构。因为这将触发未定义行为,导致程序崩溃。

在设计异步处理逻辑时,一个常见且高效的实践是将该对象的weak_ptr作为参数传递给异步任务的闭包。在工作线程实际执行任务前,通过weak_ptr调用lock函数,可以安全地检查并尝试升级为shared_ptr,确保对象依然存活,有效避免了因为对象提前析构而导致的访问悬挂指针问题。

需要注意,使用weak_ptr可能会存在对象被析构之后,任务无法被执行。如果需要保证任务被执行,请使用shared_ptr。

一、继承enable_shared_from_this

通过继承自enable_shared_from_this,我们的类能够在成员函数内部使用shared_from_this()方法,进而获得指向当前对象的共享指针。

1
2
3
4
5
6
7
8
class Myclass : public std::enable_shared_from_this<MyClass> {
public:
MyClass() = default;
void process();

private:
void process_w();
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void MyClass::process () {
// get worker thread from thread pool
auto workerThread = ThreadPool::Instance()->Get();
std::weak_ptr<MyClass> weakThis = shared_from_this();
workerThread->post([weakThis]{
// lock the weak pointer to check if 'this' still exists
auto sharedThis = weakThis.lock();
if (!sharedThis) return;
sharedThis->process_w();
});
}

void MyClass::process_w() {
// process in worker thread...
}

二、构造工厂方法

如果不想引入继承,我们可以选择设计一个工厂方法Create来实例化对象,此方法在生成对象实体的同时为成员变量mWeakThis赋值。为了进一步封装和确保安全,我们将MyClass的构造函数设为私有。

1
2
3
4
5
6
7
8
9
10
class Myclass : public std::enable_shared_from_this<MyClass> {
public:
static std::shared_ptr<MyClass> Create();
void process();

private:
MyClass() = default;
void process_w();
std::weak_ptr<MyClass> mWeakThis;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::shared_ptr<MyClass> MyClass::Create() {
auto instance = std::shared_ptr<MyClass>(new MyClass());
instance->mWeakThis = instance;
return instance;
}

void MyClass::process () {
// get worker thread from thread pool
auto workerThread = ThreadPool::Instance()->Get();
workerThread->post([mWeakThis] {
// lock the weak pointer to check if 'this' still exists
auto sharedThis = mWeakThis.lock();
if (!sharedThis) return;
sharedThis->process_w();
});
}

void MyClass::process_w() {
// process in worker thread...
}