Начать тему с функции-члена

Я пытаюсь построитьstd::thread с функцией-членом, которая не принимает аргументов и возвращаетvoid, Я не могу понять любой синтаксис, который работает - компилятор жалуется, несмотря ни на что. Как правильно реализоватьspawn() так что он возвращаетstd::thread который выполняетtest()?

#include <thread>
class blub {
  void test() {
  }
public:
  std::thread spawn() {
    return { test };
  }
};
 RnMss10 окт. 2013 г., 13:28
Вы проверяли? (Я еще не сделал этого.) Ваш код, кажется, полагается на RVO (оптимизацию возвращаемого значения), но я не думаю, что вы должны это делать. Я думаю, используяstd::move( std::thread(func) ); лучше, дляstd::thread не имеет конструктора копирования.
 Zaid Amir20 мая 2012 г., 15:02
Вы имеете в виду, что функция возвращает void, называемый void, или просто не имеет никаких параметров. Можете ли вы добавить код для того, что вы пытаетесь сделать?
 Qualia22 окт. 2015 г., 15:19
@RnMss:you can rely on RVO, с помощьюstd::move в этом случае является избыточным - если бы это было не так, и не было конструктора копирования, компилятор все равно выдал бы ошибку.

Ответы на вопрос(5)

лямбда-выражение является хорошим и чистым решением.

class blub {
    void test() {}
  public:
    std::thread spawn() {
      return std::thread( [this] { this->test(); } );
    }
};

посколькуthis-> может быть опущено, оно может быть сокращено до:

std::thread( [this] { test(); } )

или просто

std::thread( [=] { test(); } )
 abergmeier10 окт. 2013 г., 15:20
@zmb, за исключением того, что вы хотите, чтобы код компилировался на VC10, вы должны переместиться, если тип возвращаемого значения не CopyConstructable.
 09 янв. 2018 г., 09:13
@ Каждый не забывайте, что это нить здесь. Это означает, что лямбда-функция может пережить свою контекстную область. Таким образом, используя захват по ссылке ([&]), вы можете представить ошибки, как некоторые висячие ссылки. (Например,std::thread spawn() { int i = 10; return std::thread( [&] { std::cout<<i<<"\n"; } ); })
 09 сент. 2016 г., 10:37
Будь осторожен с[=], При этом вы можете случайно скопировать огромный объект. В общем, этоcode smell использовать[&] или же[=].
 09 окт. 2014 г., 12:41
RVO по-прежнему генерирует лучший код, чем семантика перемещения, и не исчезает.
 10 окт. 2013 г., 13:53
Как правило, вы не должны использоватьstd::move при возврате локальной переменной по значению. Это на самом деле тормозит RVO. Если вы просто возвращаете по значению (без перемещения), компилятор может использовать RVO, и, если это не так, стандарт говорит, что он должен вызывать семантику перемещения.

о.

I would like to add few more things related to thread.

How to work with functor and thread. Please refer to below example.

The thread will make its own copy of the object while passing the object.

#include<thread>
#include<Windows.h>
#include<iostream>

using namespace std;

class CB
{

public:
    CB()
    {
        cout << "this=" << this << endl;
    }
    void operator()();
};

void CB::operator()()
{
    cout << "this=" << this << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << "CB()=" << i << endl;
        Sleep(1000);
    }
}

void main()
{
    CB obj;     // please note the address of obj.

    thread t(obj); // here obj will be passed by value 
                   //i.e. thread will make it own local copy of it.
                    // we can confirm it by matching the address of
                    //object printed in the constructor
                    // and address of the obj printed in the function

    t.join();
}

Еще один способ достижения того же:

void main()
{
    thread t((CB()));

    t.join();
}

Но если вы хотите передать объект по ссылке, используйте следующий синтаксис:

void main()
{
    CB obj;
    //thread t(obj);
    thread t(std::ref(obj));
    t.join();
}
Решение Вопроса
#include <thread>
#include <iostream>

class bar {
public:
  void foo() {
    std::cout << "hello from member function" << std::endl;
  }
};

int main()
{
  std::thread t(&bar::foo, bar());
  t.join();
}

С учетом вашего редактирования вы должны сделать это так:

  std::thread spawn() {
    return std::thread(&blub::test, this);
  }

UPDATE: Я хочу объяснить еще несколько моментов, некоторые из них также обсуждались в комментариях.

Описанный выше синтаксис определен в терминах определения INVOKE (& # xA7; 20.8.2.1):

Define INVOKE (f, t1, t2, ..., tN) as follows:

(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T; ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item; t1.*f when N == 1 and f is a pointer to member data of a class T and t 1 is an object of type T or a
reference to an object of type T or a reference to an object of a
type derived from T; (*t1).*f when N == 1 and f is a pointer to member data of a class T and t 1 is not one of the types described in the previous item; f(t1, t2, ..., tN) in all other cases.

Еще один общий факт, на который я хочу обратить внимание, заключается в том, что по умолчанию конструктор потока будет копировать все передаваемые ему аргументы. Причина этого заключается в том, что аргументам может понадобиться пережить вызывающий поток, копирование аргументов гарантирует это. Вместо этого, если вы действительно хотите передать ссылку, вы можете использоватьstd::reference_wrapper созданоstd::ref.

std::thread (foo, std::ref(arg1));

Делая это, вы обещаете, что позаботитесь о том, чтобы аргументы все еще существовали, когда поток обрабатывает их.

Обратите внимание, что все вещи, упомянутые выше, также могут быть применены кstd::async а такжеstd::bind.

 abergmeier20 мая 2012 г., 15:37
По крайней мере, так он компилируется. Хотя я понятия не имею, почему вы передаете экземпляр в качестве второго аргумента.
 20 мая 2012 г., 15:58
Откуда вы берете это, конструктор действует как неявныйbind? Я не могу найти это где угодно.
 20 мая 2012 г., 15:49
@LCID: версия с несколькими аргументамиstd::thread конструктор работает так, как если бы аргументы были переданыstd::bind, Чтобы вызвать функцию-член, первый аргументstd::bind должен быть указателем, ссылкой или общим указателем на объект соответствующего типа.
 20 мая 2012 г., 16:39
@KerrekSB, сравните [thread.thread.constr] p4 с [func.bind.bind] p3, семантика очень похожа, она определена в терминах псевдокода INVOKE, который определяет способ вызова функций-членов
 10 окт. 2013 г., 13:56
помните, что не статические функции-члены в качестве первого параметра берут экземпляр класса (он невидим для программиста), поэтому при передаче этого метода в виде необработанной функции вы всегда столкнетесь с проблемой при несовпадении компиляции и объявления.

#include <thread>
#include <iostream>

class Wrapper {
   public:
      void member1() {
          std::cout << "i am member1" << std::endl;
      }
      void member2(const char *arg1, unsigned arg2) {
          std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl;
      }
      std::thread member1Thread() {
          return std::thread([=] { member1(); });
      }
      std::thread member2Thread(const char *arg1, unsigned arg2) {
          return std::thread([=] { member2(arg1, arg2); });
      }
};
int main(int argc, char **argv) {
   Wrapper *w = new Wrapper();
   std::thread tw1 = w->member1Thread();
   std::thread tw2 = w->member2Thread("hello", 100);
   tw1.join();
   tw2.join();
   return 0;
}

Компиляция с g ++ дает следующий результат

g++ -Wall -std=c++11 hello.cc -o hello -pthread

i am member1
i am member2 and my first arg is (hello) and second arg is (100)
 13 окт. 2016 г., 15:34
на самом деле не имеет отношения к вопросу OP, но почему вы размещаете Wrapper в куче (а не освобождаете его)? у вас есть java / c # фон?

@ hop5 и @RnMss предложили использовать лямбды C ++ 11, но если вы имеете дело с указателями, вы можете использовать их напрямую:

#include <thread>
#include <iostream>

class CFoo {
  public:
    int m_i = 0;
    void bar() {
      ++m_i;
    }
};

int main() {
  CFoo foo;
  std::thread t1(&CFoo::bar, &foo);
  t1..join();
  std::cout << foo.m_i << std::endl;
  return 0;
}

выходы

2

Переписанный образец изэтот ответ будет тогда:

#include <thread>
#include <iostream>

class Wrapper {
  public:
      void member1() {
          std::cout << "i am member1" << std::endl;
      }
      void member2(const char *arg1, unsigned arg2) {
          std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl;
      }
      std::thread member1Thread() {
          return std::thread(&Wrapper::member1, this);
      }
      std::thread member2Thread(const char *arg1, unsigned arg2) {
          return std::thread(&Wrapper::member2, this, arg1, arg2);
      }
};

int main() {
  Wrapper *w = new Wrapper();
  std::thread tw1 = w->member1Thread();
  tw1.join();
  std::thread tw2 = w->member2Thread("hello", 100);
  tw2.join();
  return 0;
}

Ваш ответ на вопрос