我想为boost线程编写一个包装器来专门化一个线程模型。我的run()
函数将成为使用boost::thread
作为聚合线程对象的同一个类的成员函数。考虑:
class Thread {
public:
Thread(...) : m_thread(&Thread::run, this) {}
private:
void run() { ... }
boost::thread m_thread;
};
This is potentially dangerous因为this
尚未完全构建。但是,如果我可以保证run()
使用的对象的所有成员在初始化boost线程之前被初始化,那么这实际上是否可以被认为是安全的?
我能想到的唯一解决方法是保证安全性是有一个子类来保证Thread
的构造函数可以使用的对象的完整构造:
class Thread {
public:
Thread(...) : m_impl(...), m_thread(&ThreadImpl::run, &m_impl) {}
private:
class ThreadImpl {
ThreadImpl(...) { }
void run() { ... }
}
ThreadImpl m_impl;
boost::thread m_thread;
};
有没有一种常见的方法可以做到这一点?对于这样一个微不足道的问题,ThreadImpl
类似乎有很多开销。
答案 0 :(得分:2)
声明成员的顺序(不是初始化列表中的顺序,所以要小心)是构造的顺序。只要构造了所有成员足以建立一致状态,如果你声明线程成员是最后的,那么你应该没问题。
但是,如果您不想依赖它,可以在构造函数的末尾以类似这样的方式启动您的线程:
// Constructor
MyThread() {
// Initialize everything else...
boost::thread t(boost::bind(&MyThread::run, this));
m_thread.swap(t);
}
关于使用this
指针的安全性,标准在12.6.2中说:
注意:因为 mem-initializer 是在范围内评估的 构造函数, this 指针可以在表达式列表中使用 mem-initializer 用于引用正在初始化的对象。
和
成员函数(包括虚拟成员函数,10.3)可以 要求正在建造的物体。
您只需要避免访问尚未构建的内容。这可以包括在初始化所有基类之前调用成员函数:
class Derived : public Base {
public:
Derived()
: Base(foo()) // foo() undefined because base class not initialized
{
}
int foo() { return 0; }
};