std :: thread具有可移动的,不可复制的参数 [英] std::thread with movable, non-copyable argument
问题描述
以下程序未在VS11 beta,gcc 4.5或clang 3.1中构建
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.
据我所知,该程序格式正确,应该可以运行.对std :: thread的要求似乎暗示可移动的不可复制参数在这里应该起作用.具体来说,它说可调用对象和每个参数都必须满足MoveConstructible要求,并且INVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...)
应该是有效表达式.
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)));
我不认为这应该包含p
的副本. gcc至少可以编译该表达式,尽管VS11不能.
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.
- 我对要求有误吗,参数必须是可复制的?
- 该标准在实现复制参数方面是否留有余地?
- 还是我尝试的实施不符合要求?
推荐答案
摘自N3337的30.3.1.2第3和4段:
From 30.3.1.2, paragraph 3 and 4 of N3337:
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
要求: F
,并且 Args
中的每个 Ti
必须满足INVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
(20.8.2)应该是有效的表达式.
Requires: F
and each Ti
in Args
shall satisfy the MoveConstructible
requirements. INVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
(20.8.2) shall be a valid expression.
效果:构造一个线程类型的对象.新的执行线程执行INVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
,并在构造线程中评估对DECAY_COPY
的调用.此调用的任何返回值都将被忽略. [注意:这意味着从调用 f
的副本中未引发的任何异常都将在构造线程中而不是新线程中抛出. — —尾注]如果INVOKE (DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
的调用因未捕获的异常终止,则应调用std :: terminate.
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 to DECAY_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 of f
will be thrown in the constructing thread, not the new thread. —end note ] If the invocation of INVOKE (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.
这篇关于std :: thread具有可移动的,不可复制的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!