Вопрос по multithreading, c++11, rvalue-reference, c++ – std :: thread с подвижным не копируемым аргументом

9

Следующая программа не встраивается в бета-версию VS11, gcc 4.5 или 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();
}

Это связано с тем, что тип аргумента не подлежит копированию, но реализация пытается его скопировать.

Насколько я могу судить, эта программа хорошо сформирована и должна работать. Требования для std :: thread, по-видимому, подразумевают, что здесь должны работать подвижные, не копируемые аргументы. В частности, он говорит, что вызываемый объект и каждый аргумент должны удовлетворять требованиям MoveConstructible, и чтоINVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...) должно быть действительным выражением.

В этом случае я думаю, что выражение получается что-то вроде:

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 - нет.

Am I wrong about the requirements and the arguments must be copyable? Does the standard leave any leeway on this issue for implementations to copy arguments? Or are the implementation I tried non-conforming?
@ Andr & # xE9; : Нет такой вещи, как передача копией; передавая аргументvalue будет копировать или перемещать в зависимости от того, передает ли вызывающий объект lvalue или rvalue. ildjarn
@ildjarn: извините, я имел в виду «по значению», а не «по копии». Мне пришло в голову, что передача аргументов по значению выберет конструктор перемещения, если таковой имеется. André Caron
Похоже, вы передаете аргумент потока путем копирования (согласно сигнатуре анонимной функции). Тип аргумента не должен бытьstd::unique_ptr<int>&& или жеconst std::unique_ptr<int>&? André Caron

Ваш Ответ

2   ответа
14

template <class F, class ...Args> explicit thread(F&& f, Args&&... args);

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.

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.

Так что да, это должно работать. Если это не так, то это ошибка в вашей реализации.

Обратите внимание, что любое перемещение / копирование параметров будет происходить в новом потоке. Вы передаете ссылки на другой поток, поэтому вам нужно убедиться, что они все еще существуют, пока этот поток не запустится.

Error: User Rate Limit Exceeded bames53
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded bames53
Error: User Rate Limit ExceededJust::Thread libraryError: User Rate Limit Exceeded
3

std::thread идиома, вы можете передать справочную оболочку:

int p;
std::thread([](int & x) { /* ... */ }, std::ref(p));

Это создает объект типаstd::reference_wrapper<int>, который имеет семантику значения и оборачивает ссылку наint (т.е. копирование псевдонима обертки ссылки).

Похожие вопросы