This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/53202] Copy constructor not called when starting a thread
- From: "redi at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 03 May 2012 00:45:01 +0000
- Subject: [Bug c++/53202] Copy constructor not called when starting a thread
- Auto-submitted: auto-generated
- References: <bug-53202-4@http.gcc.gnu.org/bugzilla/>
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