Копировать вызовы конструктора при создании нового потока

Я читаю книгу C++ Concurrency in Action, чтобы узнать больше о многопоточности и модуле памяти C++. Мне любопытно, сколько раз вызывается конструктор копирования в следующем коде:

struct func
{
    func() = default;
    func(const func& _f) {}

    void operator()() {}
};

int main()
{
    func f;
    std::thread t{ f };
    t.join();

    return 0;
}

Когда я прохожу этот код в отладчике Visual Studio 2013, я вижу конструктор копирования, вызываемый четыре раза. Он вызывается три раза из основного потока, а затем один раз из нового. Я ожидал одного, так как он сделал копию объекта для нового потока. Почему созданы три дополнительные копии?

1 ответ

Решение

Если вы установили точку останова в конструкторе копирования, вы можете увидеть контекст вызова конструктора в окне Call Stack. В режиме отладки я нашел следующие точки при вызове конструктора:

  • Сначала функциональный объект копируется во вспомогательную функцию bind

  • Затем функциональный объект перемещается во внутренний функциональный объект. _Bind

  • После этого класс для запуска потоков _LaunchPad создано. В
    конструктор, он принимает ссылку Rvalue на экземпляр _Bind, поэтому мы имеем
    еще один вызов конструктора перемещения

  • переместить конструктор _LaunchPad вызывается, когда его копия создается в новом потоке.

Таким образом, у нас есть 4 вызова конструктора копирования в вашем случае. Если бы вы добавили конструктор перемещения, вы бы увидели 1 конструктор копирования и 3 вызова конструктора перемещения.

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

Другие вопросы по тегам