【发布时间】:2019-09-13 06:18:16
【问题描述】:
我想实现一个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;
}
在cmets中,cmd线程结束后对象仍然存在,我想知道如何实现这样的功能。
编辑
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
关闭
我弄错了test,实际上线程结束后对象被删除了。下面的test加上一个额外的成员变量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;
}
flowwing 输出证明该对象已被删除。
10 thread begins
10 thread ends
destructor
-572662307 OK
但正如一些好心人所说,这不是一个好的设计,请尽量避免。
【问题讨论】:
-
“但不起作用” ...继续,告诉我们血淋淋的细节。发生了什么?如果
Cmd *p = new Cmd(); delete p; p->ok()打印了您的信息,您会感到惊讶吗? -
如果
p->ok()在你的情况下打印我的消息,我会感到惊讶,至少它是UB。 -
我希望
thread在我的情况下删除cmd。 -
您正在测试 UB。但是如果你有 UB,你就不能依赖你的测试。在已删除对象上调用成员函数是 UB,不需要崩溃。
ok()正在努力工作。 -
一个对象自发地窃取它自己的所有权然后结束它自己的生命周期是非常不寻常的。这种类型很容易使用不正确,使设计避免。好的软件设计的基本规则之一是使代码易于正确使用,而难以正确使用。
标签: c++ memory-management stdthread