Search code examples
c++constructorboost-thread

Initialize boost thread in object constructor?


I want to write a wrapper for boost thread to specialize a threading model. My run() function is going to be a member function of the same class that is using boost::thread as the aggregate thread object. Consider:

class Thread {
public:
  Thread(...) : m_thread(&Thread::run, this) {}

private:
  void run() { ... }
  boost::thread m_thread;
};

This is potentially dangerous because this is not yet fully constructed. However, if I can guarantee that all members of the object used by run() are initialized prior-to initialization of the boost thread, could this actually be considered safe?

The only workaround I can think of that guarantees safety is to have a subclass that guarantees full construction of an object that can be used by the constructor of 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;
};

Is there a common way to do this? The ThreadImpl class seems like a lot of overhead for such a trivial issue.


Solution

  • The order that members are declared (not the order in the initializer list, though, so be careful) is the order of construction. You should be fine if you declare the thread member last as long as having all members constructed is sufficient to establish a consistent state.

    However, if you don't want to rely on that, you can start your thread at the end of the constructor with something like this:

    // Constructor
    MyThread() {
      // Initialize everything else...
    
      boost::thread t(boost::bind(&MyThread::run, this));
      m_thread.swap(t);
    }
    

    Regarding the safety of using the this pointer, the standard says in 12.6.2:

    Note: because the mem-initializer are evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized.

    and

    Member functions (including virtual member functions, 10.3) can be called for an object under construction.

    You just have to avoid accessing what has not yet been constructed. That can include calling member functions before all base classes have been initialized:

    class Derived : public Base {
    public:
      Derived()
        : Base(foo())  // foo() undefined because base class not initialized
      {
      }
    
      int foo() { return 0; }
    };