std :: thread, конструктор класса и деструктор

При тестировании потоков в C ++ 11 я создал следующий пример:

#include <iostream>
#include <thread>

class Foo {
public:
Foo(void) {
std::cout << "Constructor called: " << this << std::endl;
}
~Foo(void) {
std::cout << "Destructor called: " << this << std::endl;
}
void operator()() const {
std::cout << "Operatior called: " << this << std::endl;
}
};

void test_normal(void) {
std::cout << "====> Standard example:" << std::endl;
Foo f;
}

void test_thread(void) {
std::cout << "====> Thread example:" << std::endl;
Foo f;
std::thread t(f);
t.detach();
}int main(int argc, char **argv)
{
test_normal();
test_thread();

for(;;);
}

Который печатает следующее:

введите описание изображения здесь

Почему деструктор вызывается 6 раз для потока? И почему поток сообщает о разных местах памяти?

РЕДАКТИРОВАТЬ
При добавлении перемещения и копирования вывода конструктора:

введите описание изображения здесь

2

Решение

Добавьте конструктор копирования и переместите конструктор в свой класс.

Foo(Foo const&) { std::cout << "Copy Constructor called: " << this << std::endl; }
Foo(Foo&&) { std::cout << "Move Constructor called: " << this << std::endl; }

Теперь, если вы запустите код вывод (на gcc 4.7.2) выглядит так:

====> Standard example:
Constructor called: 0xbff696ff
Destructor called: 0xbff696ff
====> Thread example:
Constructor called: 0xbff696ff
Copy Constructor called: 0xbff696cf
Move Constructor called: 0x93a8dfc
Destructor called: 0xbff696cf
Destructor called: 0xbff696ff
Operator called: 0x93a8dfc
Destructor called: 0x93a8dfc

Как видите, количество вызовов деструктора совпадает с количеством вызовов различных конструкторов.

Я подозреваю, что gcc удаляет несколько вызовов конструирования копирования / перемещения, которые MSVC, похоже, выполняет, поэтому вызовов деструкторов меньше, чем в вашем примере.


Кроме того, вы можете полностью избежать копирования std::moveв Foo Объект для конструктора потока.

В test_thread изменить строку построения резьбы на

std::thread t(std::move(f));

Теперь вывод выглядит так:

====> Standard example:
Constructor called: 0xbfc23e2f
Destructor called: 0xbfc23e2f
====> Thread example:
Constructor called: 0xbfc23e2f
Move Constructor called: 0xbfc23dff
Move Constructor called: 0x9185dfc
Destructor called: 0xbfc23dff
Destructor called: 0xbfc23e2f
Operator called: 0x9185dfc
Destructor called: 0x9185dfc
3

Другие решения

Функциональный объект будет перемещен или скопирован. Вы не учли в своем выводе ни для одного из них.

6

Потому что ваш Foo находится в стеке, а не в куче. Это означает, что вы размещаете новый внутри test_thread, затем он копируется, когда вы вызываете std :: thread (f), и снова внутри thread (f).

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

2

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

https://ideone.com/wvctrl

#include <iostream>
#include <thread>

class Foo {
public:
Foo(Foo&& f) {
std::cout << "Constructor Foo&& called: " << this << std::endl;
}
Foo(const Foo& f) {
std::cout << "Constructor const Foo& called: " << this << std::endl;
}
Foo(void) {
std::cout << "Constructor called: " << this << std::endl;
}
~Foo(void) {
std::cout << "Destructor called: " << this << std::endl;
}
void operator()() const {
std::cout << "Operatior called: " << this << std::endl;
}
};

void test_normal(void) {
std::cout << "====> Standard example:" << std::endl;
Foo f;
}

void test_thread(void) {
std::cout << "====> Thread example:" << std::endl;
Foo f;
std::thread t(f);
t.detach();
}int main(int argc, char **argv)
{
test_normal();
test_thread();

for(;;);
}

это показывает, что все ctors соединяются с dtors.

Также посмотрите на это так:

Правило Три становится Правилом Пяти с C ++ 11?

1
По вопросам рекламы [email protected]