This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/53202] Copy constructor not called when starting a thread


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53202

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|ASSIGNED                    |NEW
                 CC|                            |jason at gcc dot gnu.org
          Component|libstdc++                   |c++
         AssignedTo|redi at gcc dot gnu.org     |unassigned at gcc dot
                   |                            |gnu.org

--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> 2012-05-03 00:45:01 UTC ---
Here's a reduced version that only needs -std=c++11 and not -pthread

#include <tuple>

template<typename Callable>
  struct Bind_simple
  {
    explicit
    Bind_simple(const Callable& callable)
    : _M_bound(callable)
    { }

    Bind_simple(const Bind_simple&) = default;
    Bind_simple(Bind_simple&&) = default;

    auto operator()() -> decltype((*(Callable*)0)())
    {
      return std::get<0>(_M_bound)();
    }

  private:

    std::tuple<Callable> _M_bound;
  };

template<typename Callable>
  Bind_simple<Callable>
  bind_simple(Callable& callable)
  {
    return Bind_simple<Callable>(callable);
  }

struct thread
{
  struct ImplBase { };

  template<typename T>
    struct Impl : ImplBase {
      T t;
      Impl(T&& t) : t(std::move(t)) { }
    };

  template<typename T>
    thread(T& t)
    {
      auto p = make_routine(bind_simple(t));

      p->t();

      delete p;
    }

  template<typename Callable>
    Impl<Callable>*
    make_routine(Callable&& f)
    {
      return new Impl<Callable>(std::forward<Callable>(f));
    }
};


class background_hello
{
public:
    background_hello()
    {
        __builtin_printf("default ctor called, this=%p\n", this);
    }

    background_hello(const background_hello &)
    {
        __builtin_printf("copy ctor called\n");
    }

    background_hello(background_hello &&)
    {
        __builtin_printf("move ctor called\n");
    }

    void operator ()() const
    {
        __builtin_printf("void background_hello::operator()() called,
this=%p\n", this);
    }

    ~background_hello()
    {
        __builtin_printf("destructor called, this=%p\n", this);
    }

};

int main()
{
    background_hello bh;
    thread t(bh);
}

This still produces the wrong result:

default ctor called, this=0x7fffe4a2c3bf
destructor called, this=0x7fffe4a2c38f
void background_hello::operator()() called, this=0xd9d028
destructor called, this=0xd9d028
destructor called, this=0x7fffe4a2c3bf


Looking at the gimple dump I see that the
  thread::Impl<Bind_simple<background_hello()>>
constructor doesn't initialize its Bind_simple member:


thread::Impl<T>::Impl(T&&) [with T = Bind_simple<background_hello>] (struct
Impl * const this, struct Bind_simple & t)
{
  struct Bind_simple * D.8909;

  thread::ImplBase::ImplBase (this);
  try
    {

    }
  catch
    {
      D.8909 = &this->t;
      Bind_simple<background_hello>::~Bind_simple (D.8909);
    }
}


If the Bind_simple object isn't move-constructed then its background_hello
object won't be either, which explains the missing constructor calls.

If Bind_simple<Callable> stores a Callable directly instead of as
tuple<Callable> then the problem goes away and I see three constructors called.


I think at this point it looks like a G++ issue


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]