I have a function that takes a long time to run, but thankfully it runs asynchronously. I want to take the result of this function call and set it to a class instance's private variable. Seems easy:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
void Do() {
auto lambda = [this](int val) {
// Some processing...
var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
A* a = new A;
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
The problem is adding the following line to main, right before the comment:
delete a;
Now when LongRunningAsync invokes the callback, it will attempt to modify a member variable of a deleted instance (which is UB).
Is there a way to salvage this approach? I've recently learned about the following solution:
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
std::weak_ptr<A> weak = shared_from_this();
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) return;
// Some processing...
shared->var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
auto a = std::make_shared<A>();
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
But it requires changing all A variables to shared_ptr. Is there a less intrusive way to make this work?
One possible solution is to just encapsulate the state you need into a shared_ptr member variable and then capture that by value into the closure that runs asynchronously.
Something like the following
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
auto lambda = [member_shared_state](int val) {
member_shared_state->var_ = val;
};
LongRunningAsync(lambda);
}
....
};
Here's a solution based on Curious's approach, but that doesn't force me to change all pointers to A objects to shared_ptr:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
A() : var_(std::make_shared<int>()) {}
void Do() {
std::weak_ptr<int> weak = var_;
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) {
return;
}
// Some processing...
*shared = val;
};
LongRunningAsync(lambda);
}
private:
std::shared_ptr<int> var_;
};
int main() {
A* a = new A;
a->Do();
delete a;
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
Related
In C++ is there a way, using raw pointers or otherwise to trigger some action when the pointed to object changes?
Scenario:
class A
{
double var;
B var2 {&var};
}
class B
{
double* pVar;
B (double* _var ) { pVar = _var};
}
I have functions inside class B that will get called whenever member variable var changes value. At the moment I would need these functions to be public so they can be called manually from class A, this could be achieved by using a setter for var. If I wanted to keep the function inside class B private (as it is called by other events internal to class B) what are my options?
This is an example of the observer pattern.
So what you need is to trigger a function call to another object
when the value of your object is changed through a setter method.
#include <functional>
#include <iostream>
//-----------------------------------------------------------------------------
// the class with the member variable that can change
// and to which another class can react.
// This is a simple example where only one "callback" function
// can be registered. In the typical observer pattern
// there can be multiple callbacks registered.
class Observee
{
public:
// set notification function to a function that does nothing
// "null strategy pattern"
Observee() :
m_notify_observer_fn{ [](int) {} }
{
}
// let another object pass in a function that will be called
// when the value is changed
void OnValueChanged(std::function<void(int)> notify_observer_fn)
{
m_notify_observer_fn = notify_observer_fn;
}
// to change the member value AND notify the other object
// that the value has changed we need a setter function.
void set_value(int value)
{
// check if the value really has changed
if (m_value != value)
{
// set the member value
m_value = value;
// then notify the observer of the new value
// by calling the notification function
m_notify_observer_fn(m_value);
}
}
private:
std::function<void(int)> m_notify_observer_fn;
int m_value{};
};
//-----------------------------------------------------------------------------
// The class that wants to get a notification when the value
// of the other class changes (role is an Observer)
class Observer
{
public:
explicit Observer(Observee& observee)
{
// Set the callback in the observee to the OnValueChanged
// function of this object (the function passed is called a lambda funtion)
observee.OnValueChanged([this](int value)
{
OnValueChanged(value);
});
}
private:
void OnValueChanged(int value)
{
std::cout << "Value changed to " << value << "\n";
}
};
//-----------------------------------------------------------------------------
int main()
{
// make instances of both classes.
Observee observee;
Observer observer{ observee };
// now set the value
// this will change the member in observee
// and then call the method in the observer for you
observee.set_value(42);
return 0;
}
Question : If I wanted to keep the function inside class B private (as it is called by other events internal to class B) what are my options?
You can call a private function of class B while coding class A using friend attribute.
class B
{
friend class A;
private:
void foo() { std::cout << "using foo." << std::endl; }
};
class A
{
private:
B b;
public:
void bar(){ b.foo(); }
};
int main()
{
A a;
a.bar();
return 0;
}
About the callback to be call when a double variable change its value:
No you can't do it with a raw pointer.
You got at least two ways of doing it.
The first way is what you outlined : use a setter function.
The second is to make a class that own the value and that overloading operator= is able to call the callback.
I'll sketch something here to make you understand better:
template<class T>
class Owner{
using FuncType = std::function<void(Owner<T>&)>;
public:
Owner(){}
Owner(const T& init){
_var = init;
}
Owner(const Owner<T>& init){
_var = init;
}
operator T(){
return _var;
}
auto& operator =(const T& rvalue){
_var = rvalue;
_on_change();
return *this;
}
auto& operator =(const Owner<T>& rvalue){
_var = rvalue;
_on_change();
return *this;
}
const T& get() const { //don't make it non const or
//you will lose ownership to value of _var
return _var;
}
void set(const T& val){
_var = val;
_on_change();
}
void set(const Owner<T>& val){
_var = val;
_on_change();
}
void set_handler(FuncType func)
{
_func = func;
}
private:
void _on_change(){
if(_func)
_func(*this);
}
private:
T _var{};
FuncType _func{};
};
int main()
{
Owner<double> var{};
var.set_handler([](Owner<double>& ch){
std::cout << "Value changed: " << (double) ch << std::endl;
});
var = 1.0;
return 0;
}
In case my phrasing wasn't clear, here's the code.
struct token {};
struct resumable {
struct promise_type {
auto get_return_object() {
return coroutine_handle<promise_type>::from_promise(*this);
}
suspend_never initial_suspend() { return {}; }
suspend_always final_suspend() { return {}; }
auto await_transform(token)
{
struct awaiter {
awaiter(promise_type& p) : m_promise(p) {}
bool await_ready() { return false; }
void await_suspend(coroutine_handle<>) {}
int await_resume() {
int _result = 5;
return _result;
}
promise_type& m_promise;
};
return awaiter(*this);
}
};
bool resume() {
if (!m_handle.done()) {
m_handle.resume();
}
return !m_handle.done();
}
resumable(coroutine_handle<promise_type> h) : m_handle(h) {}
private:
coroutine_handle<promise_type> m_handle;
};
void someAsyncKernelApi(void* callbackContext)
{
// When async work is done, enqueues callbackContext into the completion queue.
}
token WrappedAsyncKernelApi(void* callbackContext)
{
someAsyncKernelApi(callbackContext);
return token{};
}
resumable coro()
{
int _async_result = co_await WrappedAsyncKernelApi(/* Is it possible to pass address of this own
spawned coroutine to get called later on?
Same address the pointer "r_ptr" at main
is pointing to*/);
}
int main()
{
resumable* r_ptr = new auto(coro());
}
Few solutions I can think of right now are either initial suspend when the coroutine is spawned and store the pointer in an arbitrary struct and pass from that stored struct, or awaiting a resumable pointer on first await.
But I feel like there's much cleaner way to do this.. Is there any?
I have class MyClass that can be modified by calling setX.
I want to know if an object of MyClass has been changed by calling isChanged.
In the code below, I don’t like to add setDirty or m_dataChanged in every method that can change the state of an object.
class ChangesHolder
{
private:
bool m_isChanged;
// boost::signals2::signal<void()> m_dataChanged;
// long m_stamps;
public:
ChangesHolder()
: m_isChanged{false}
// , m_stamps{0}
{
// m_dataChanged.connect(std::bind(&ChangesHolder::setDirty, this));
}
bool isChanged() const
{
return m_isChanged;
// return (m_stamps == 0);
}
void resetChanges()
{
m_isChanged = false;
// m_stamps = 0;
}
protected:
void setDirty()
{
m_isChanged = true;
// ++m_stamps;
}
}
class MyClass : public ChangesHolder
{
private:
int m_x;
public:
void setX(int x)
{
if (m_x != x)
{
m_x = x;
setDirty();
// m_dataChanged();
}
}
}
I want to register such methods like this:
template<typename ... Funcs>
void startTrack(Funcs ... funcs)
{
auto connect = [&](auto func)
{
// connect func to setDirty
};
do_foreach(connect, funcs ...);
}
MyClass::MyClass()
{
startTrack(&MyClass::setX, &MyClass::setY);
}
How can this be done or maybe there are other ways to do it?
Okay, so I'm writing a simple GUI framework. I stumbled across lambda expressions and thought they'd be a good way to do callbacks. But I can't figure out how to retain the expression in class (very simplified example code below).
class class1
{
public:
class1(auto callback);
private:
const auto mCallback
};
class1::class1(auto callback) : mCallback(callback)
{
}
int main()
{
auto thiscode = [] (int id)
{
std::cout<<"callback from..." << id << std::endl;
};
class1 c1 = class1(thiscode);
}
I end up with this error,
error: non-static data member declared 'auto'
Which I suppose makes sense, it can't determine the size at run time. In fact, below C++14 it won't even allow me to pass auto callback as a paramter to the constructor. (I think that changed in a readying process for concepts?).
How do I get around this? I don't mind having to do something weird, anything that allows me to retain a reference to the passed lambda expression - I'm golden with.
You can use std::function to store thiscode.
Something like this:
#include <functional>
#include <iostream>
class class1 {
public:
class1(std::function<void(int)> callback) : mCallback{callback} {};
void do_callback() { mCallback(3); };
private:
const std::function<void(int)> mCallback;
};
int main()
{
auto thiscode = [](int id) {
std::cout<<"callback from..." << id << std::endl;
};
class1 c1 = class1(thiscode);
c1.do_callback();
return 0;
}
See live demo here.
You can hold them with templates
template<typename T>
class class1
{
public:
class1(T callback): mCallback{std::move(callback)} {}
private:
const T mCallback
};
template<typename T>
auto makeClass1(T&& callback) {
return class1<std::decay_t<T>>{std::forward<T>(callback)};
}
int main()
{
auto thiscode = [] (int id)
{
std::cout<<"callback from..." << id << std::endl;
};
auto c1 = makeClass1(thiscode);
}
Or alternatively, you can hold them with std::function:
class class1
{
public:
class1(std::function<void(int)> callback);
private:
const std::function<void(int)> mCallback
};
int main()
{
auto thiscode = [] (int id)
{
std::cout<<"callback from..." << id << std::endl;
};
class1 c1 = class1(thiscode);
}
I have the following class:
class Timer
{
public:
Timer(){};
~Timer(){};
void timer(int);
//...
private:
//...
};
My function timer(int value) is a callback that I use in glutTimerFunc(), inside the function timer(int value) i need to use the function timer again, something like this:
void Timer::timer(int value)
{
//...
glutTimerFunc(state->getTimer(), this->timer, 0);
}
How can i do it without using a static function?
you'll need a global dispatcher that turns the int passed to glutTimerFunc into a c++ callback (member function, lambda, etc)
something like this
struct timer_dispatch
{
using callback_t = std::function<void()>;
int start_timer(int msecs, callback_t callback) {
std::unique_lock<std::mutex> lock(_mutex);
int ident = _next_id++;
_callbacks.emplace(ident, std::move(callback));
glutTimerFunc(msecs, &timer_dispatch::dispatch_timer, ident);
return ident;
}
// implement similar function for stop timer - don't forget the mutex
void stop_timer(int ident) {
std::unique_lock<std::mutex> lock(_mutex);
_callbacks.erase(ident);
}
static timer_dispatch& instance() {
static timer_dispatch _;
return _;
}
private:
// private constructor ensures use via the instance() static method;
timer_dispatch() = default;
static void dispatch_timer(int ident) {
auto self = instance();
std::unique_lock<std::mutex> lock(self._mutex);
auto it = self._callbacks.find(ident);
if (it != self._callbacks.end()) {
auto my_copy = std::move(it->second);
self._callbacks.erase(it);
lock.unlock();
my_copy();
}
}
private:
std::unordered_map<int, callback_t> _callbacks;
std::mutex _mutex;
int _next_id = 0;
};
now use like so:
// start my timer:
void myclass::start_alien() {
...
_alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
...
}
void myclass::on_alien_timeout() {
// make alien do something, possibly restart a timer...
_alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
}
void myclass::on_alien_killed() {
timer_dispatch::instance().stop_timer(_alien_timer_id);
_alien_timer_id = -1;
}