9

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

Следующая программа не встраивается в бета-версию 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 - нет.

  1. Am I wrong about the requirements and the arguments must be copyable?
  2. Does the standard leave any leeway on this issue for implementations to copy arguments?
  3. Or are the implementation I tried non-conforming?
  • Error: User Rate Limit Exceeded

    от bames53
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit ExceededJust::Thread libraryError: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от bames53
  • @ Andr & # xE9; : Нет такой вещи, как передача копией; передавая аргументvalue будет копировать или перемещать в зависимости от того, передает ли вызывающий объект lvalue или rvalue.

    от ildjarn
  • Похоже, вы передаете аргумент потока путем копирования (согласно сигнатуре анонимной функции). Тип аргумента не должен бытьstd::unique_ptr<int>&& или жеconst std::unique_ptr<int>&?

    от André Caron
  • @ildjarn: извините, я имел в виду «по значению», а не «по копии». Мне пришло в голову, что передача аргументов по значению выберет конструктор перемещения, если таковой имеется.

    от André Caron
  • 3

    Как альтернатива и как стандарт

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

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

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

  • 14

    От 30.3.1.2, параграфы 3 и 4 N3337:

    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.

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

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