Reputation: 7457
I have a base using std::thread _threadCall
in its destructor, but I need to initialize it from the subclass (imagine I have several subclasses, all initializing differently _threadCall
).
class QueryBase
{
std::condition_variable _cv;
bool _run{ true };
std::thread _threadCall;
virtual ~QueryBase();
void virtual CallRunner()=0;
}
QueryBase::~QueryBase()
{
_run = false;
_cv.notify_one();
_threadCall.join();
}
subclass:
class __declspec(dllexport) AsyncQuery: public QueryBase
{
protected:
MessageChangedCallback _log{};
public:
AsyncQuery(MessageChangedCallback fn);
void Add(const std::string& msg);
void CallRunner() override;
}
AsyncQuery::AsyncQuery(MessageChangedCallback fn)
: QueryBase(), _log(fn),
_threadCall([&] { CallRunner(); }) //E0292 _threadCall is a non-static member
// or base class of class AsyncQuery
{
}
Can I initialize it from the subclass constructor or in some way ? if not I have the obligation to write the same dtor in every single sublass ?
As alternative, I thought about declaring a delegate in the base-class, and I "define" it in the subclasses:
class QueryBase
{
std::function<void()> f;
void virtual CallRunner()=0;
QueryBase::QueryBase() : _threadCall(f)
{
}
AsyncQuery::AsyncQuery(MessageChangedCallback fn)
: _log(fn)
{
f = [&] {CallRunner();};
}
Where CallRunner()
is defined (overrides a pure virtual) only in subclasses. Any pros/cons about this ?
Upvotes: 1
Views: 110
Reputation: 30128
It is usually bad idea to use inheritance in this way, maybe you should use std::jthread
, but design discussions aside...
Way to do delayed construction is to use std::optional
member.
struct B {
std::optional<std::thread> t;
~B() {
assert(t.has_value());
std::cout << "joining" << std::endl;
t->join();
std::cout << "joined" << std::endl;
}
};
struct D : public B {
D() {
t.emplace([] { std::cout << "hello from derived" << std::endl; });
}
};
int main() { D d; }
Upvotes: 1
Reputation: 4249
Just use C++20 std::jthread
with a std::stop_token
:
std::jthread my_async_q{
[](std::stop_token finish){
while(not finish.stop_requested())
{/*repeat the job*/};
};//lambda
};//my_async_q
All your dll or any other extension code needs provide is a function foo
or a function object that satisfies std::invocable<decltype (foo),std::stop_token>
.
Then you can restart a thread like:
//if (my_async_q.joinable())
my_async_q.request_stop();
//Join before renewal:
my_async_q = std::jthread{foo};
The join
member is automatically invoked upon destruction. This single standard class encapsulate all the functionality you are trying to achieve, without needing dynamic polymorphism.
Upvotes: -1