The following program doesn't build in VS11 beta, gcc 4.5, or clang 3.1
#include <thread>
#include <memory>
int main() {
std::unique_ptr<int> p;
std::thread th([](std::unique_ptr<int>) {
},std::move(p));
th.join();
}
This is because the argument type is not copyable, but the implementation attempts to copy it.
As far as I can tell, this program is well formed and should work. The requirements for std::thread seem to imply that movable, non-copyable arguments should work here. Specifically it says that the callable object and each argument shall satisfy the MoveConstructible requirements, and that INVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...)
shall be a valid expression.
In this case I think expression works out to something like:
template <class T> typename std::decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }
std::unique_ptr<int> p;
auto f = [](std::unique_ptr<int>) {};
decay_copy(f)(decay_copy(std::move(p)));
And I don't think this is supposed to involve a copy of p
. gcc at least can compile this expression, though VS11 does not.
From 30.3.1.2, paragraph 3 and 4 of N3337:
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
Requires:
F
and eachTi
inArgs
shall satisfy theMoveConstructible
requirements.INVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
(20.8.2) shall be a valid expression.Effects: Constructs an object of type thread. The new thread of execution executes
INVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
with the calls toDECAY_COPY
being evaluated in the constructing thread. Any return value from this invocation is ignored. [ Note: This implies that any exceptions not thrown from the invocation of the copy off
will be thrown in the constructing thread, not the new thread. —end note ] If the invocation ofINVOKE (DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
terminates with an uncaught exception, std::terminate shall be called.
So yes, this should work. If it doesn't, then that's a bug in your implementation.
Do note that any parameter movement/copying will happen on the new thread. You're passing references to another thread, so you need to make sure that they still exist until that thread starts.
As an alternative, and as the standard std::thread
idiom, you can pass a reference wrapper:
int p;
std::thread([](int & x) { /* ... */ }, std::ref(p));
This creates an object of type std::reference_wrapper<int>
, which has value semantics and wraps a reference to an int
(i.e. copying the wrapper aliases the reference).
std::unique_ptr<int>&&
orconst std::unique_ptr<int>&
- André Caron 2012-04-03 21:36