我想实现一个<script src="https://d3js.org/d3.v5.min.js"></script>
类,该类在另一个线程中完成某些工作,并且我不想让用户手动删除该对象。我的cmmand
类如下:< / p>
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; }
};
就像在评论中一样,该对象在cmd线程完成后仍然存在,我想知道如何实现这种功能。
编辑
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
何时完成,因此,不断发展的用例将导致UB。
cmd
已关闭
我在测试方面犯了一个错误,实际上该对象在线程结束后被删除了。使用附加的成员变量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;
}
但是正如某些同仁所建议的那样,这不是一个好的设计,请尽量避免。
答案 0 :(得分:1)
您可以使用std::future而不是线程来指示状态。然后,您可以等待任务完成,也可以完全忽略将来。
#include <future>
#include <chrono>
#include <mutex>
#include <iostream>
class Cmd {
public:
std::future<void> run() {
std::lock_guard<std::mutex> lock(startMutex);
if (started) {
throw std::logic_error("already started");
}
started = true;
// Take copies here, so that it doesn't matter if Cmd is destroyed
int i_ = i;
return std::async(std::launch::async, [i_]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << i_ << std::endl;
});
}
int i = 0;
private:
std::mutex startMutex;
bool started = false;
};
int main() {
auto p = std::make_unique<Cmd>();
p->i = 10;
auto f = p->run();
p.reset();
// Do some other work
// Wait for the task to finish (or use f.get() if there is no need to
// do some other work while waiting)
if (f.valid()) {
std::future_status operation;
do {
// Do some other work
operation = f.wait_for(std::chrono::milliseconds(1));
} while (operation != std::future_status::ready);
}
}
答案 1 :(得分:0)
有两种方法可以自动删除动态创建的内存。
在客户端代码(主要功能)中,应使用unique_pointer之类的智能指针,以便一旦对象超出范围,它将自动在unique_poiter析构函数中释放
您可以创建自己的smart pointer,它将成为Cmd类的包装器。并且不得不重载一些运算符。该智能指针还将处理析构函数中动态分配的内存。客户端代码在动态创建Cmd对象时应使用此智能指针。