Я хочу реализовать класс cmmand
, который выполняет некоторую работу в другом потоке, и я не хочу позволять пользователям удалять этот объект вручную. Мой command
класс выглядит так:
class Cmd {
public:
void excute() {
std::cout << "thread begins" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2)); // do some work
std::cout << "thread ends" << std::endl;
}
void run() {
// I want std::unique_ptr to delete 'this' after work is done,but does't work
std::thread td(&Cmd::excute, std::unique_ptr<Cmd>(this));
td.detach();
}
// test if this object is still alive
void ok() { std::cout << "OK" << std::endl; }
};
Я использую это так:
int main() {
Cmd *p = new Cmd();
p->run();
// waiting for cmd thread ends
std::this_thread::sleep_for(std::chrono::seconds(3));
p->ok(); // I thought p was deleted but not
return 0;
}
Как и в комментариях, объект все еще жив после завершения потока cmd, я хочу знать, как реализовать такую функциональность.
EDIT
пользователи cmd
не знают, когда закончится cmd
, поэтому текущий вариант использования приведет к UB.
std::unique_ptr<Cmd> up(new Cmd); // or just Cmd c;
up->run();
// cmd will be deleted after out of scope but cmd::excute may still need it
ЗАКРЫТО
Я допустил ошибку в тесте, фактически объект удаляется после завершения потока. Это более понятно при следующем тесте с дополнительной переменной-членом int i
.
#include <functional>
#include <iostream>
#include <stack>
#include <thread>
using namespace std;
class Cmd {
public:
~Cmd() { std::cout << "destructor" << std::endl; }
void excute() {
std::cout << i << " thread begins" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2)); // do some work
std::cout << i << " thread ends" << std::endl;
}
void run() {
// I want std::unique_ptr to delete 'this' after work is done,but it seems
// not working
std::thread td(&Cmd::excute, std::unique_ptr<Cmd>(this));
td.detach();
}
// test if this object is still alive
void ok() { std::cout << i << " OK" << std::endl; }
int i;
};
int main() {
Cmd *p = new Cmd();
p->i = 10;
p->run();
// waiting for cmd thread ends
std::this_thread::sleep_for(std::chrono::seconds(3));
p->ok(); // I thought p was deleted but not
return 0;
}
Вывод потока показал, что объект удален.
10 thread begins
10 thread ends
destructor
-572662307 OK
Но, как полагают некоторые добрые парни, это не очень хороший дизайн, избегайте его, как можете.