C ++ метод в потоке.Разница между передачей: объект, адрес объекта, std :: ref объекта - PullRequest
0 голосов
/ 18 декабря 2018

Я пытаюсь выполнить метод объекта в потоке C ++.

Я могу это сделать, передав адрес метода и объект (или адрес объекта, или std :: ref (my_obj)) конструктору потока.

Я заметил, чтоесли я передаю объект, а не адрес объекта или std :: ref (my_obj), то объект копируется дважды (я печатаю некоторую информацию в конструкторе копирования, чтобы увидеть это).

Вот код:

class Warrior{
    string _name;
public:
    // constructor
    Warrior(string name): _name(name) {}

    // copy constructor (prints every time the object is copied)
    Warrior(const Warrior & other): _name("Copied " + other._name){
        cout << "Copying warrior: \"" << other._name;
        cout << "\" into : \"" << _name << "\"" << endl;
    }

    void attack(int damage){
        cout << _name << " is attacking for " << damage << "!" << endl;
    }
};

int main(){
    Warrior conan("Conan");

    // run conan.attack(5) in a separate thread
    thread t(&Warrior::attack, conan, 5);
    t.join(); // wait for thread to finish

}

В этом случае я получаю вывод

Copying warrior: "Conan" into : "Copied Conan"
Copying warrior: "Copied Conan" into : "Copied Copied Conan"
Copied Copied Conan is attacking for 5!

Хотя, если я просто передам &conan или std::ref(conan) как секундуаргумент thread t(...) (вместо передачи conan), вывод просто:

Conan is attacking for 5!

У меня есть 4 сомнения:

  1. Почему это у меня есть2 копии объекта вместо 1?

    Я ожидал, что, передав экземпляр объекта в конструктор потока, объект будет скопирован один раз в собственный стек потока, а затем будет вызван метод attack()на этой копии.

  2. Какова точная причина, по которой конструктор потока может принять объект, адрес или std::ref?Используется ли эта версия конструктора (которую, я признаю, я не до конца понимаю)

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

    во всех 3 случаях?

  3. Если мы исключим первый случай (поскольку он неэффективен), что мне следует использовать между &conan и std::ref(conan)?

  4. Это как-то связано с синтаксисом, требуемым std::bind?

1 Ответ

0 голосов
/ 18 декабря 2018

Почему у меня есть 2 копии объекта вместо 1?

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

Какова точная причина, по которой конструктор потока может принять объект, адрес илиstd :: ref?Использует ли эта версия конструктора (который, я признаю, я не до конца понимаю)

std::thread в основном запускает новый поток с помощью вызова, подобного

std::invoke(decay_copy(std::forward<Function>(f)), 
            decay_copy(std::forward<Args>(args))...);

std::invoke создан для обработки всех видов вызываемых типов, и один из них, когда он имеет указатель на функцию-член и объект, и вызывает функцию соответствующим образом.Он также знает о std::reference_wrapper и может обрабатывать вызов указателя на функцию-член на std::reference_wrapper объекте.

Если мы исключаем первый случай (так как он неэффективен), что я должениспользуйте между &conan и std::ref(conan)?

Это в основном основано на мнении.По сути, они оба делают одно и то же, хотя первую версию писать короче.

Это как-то связано с синтаксисом, необходимым для std::bind?

Вид,std::bind operator() также реализован с использованием std::invoke, поэтому у них очень общий интерфейс.


Все это говорит о том, что вы можете использовать лямбда-выражения для создания общего интерфейса.

thread t(&Warrior::attack, conan, 5);

можно переписать как

thread t([&](){ return conan.attack(5); });

И вы можете использовать эту форму практически для любой другой функции, которую вы хотите вызвать.Я считаю, что анализировать лямбду легче.

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