c++ - How to pass a lambda function an instantiantion of a class with a template class -



c++ - How to pass a lambda function an instantiantion of a class with a template class -

i'm trying create c++ class wraps posix timer functions have timer class can used in flexible manner , pass in user defined info ( can't done straight posix c timer functions ). have following:

timer class implementation:

#include <functional> #include <utility> #include <sys/time.h> #include <signal.h> #include <time.h> #include <string.h> template<typename f> class timer { public: struct sigaction signalaction; struct sigevent signalevent; struct itimerval timer_ms; timer_t timerid; timer(f callback, int milliseconds) : ontimeout(std::move(callback)) { timer_ms.it_value.tv_sec = milliseconds / 1000; timer_ms.it_value.tv_usec = ( milliseconds % 1000 ) / 1000; timer_ms.it_interval.tv_sec = milliseconds / 1000; timer_ms.it_interval.tv_usec = ( milliseconds % 1000 ) / 1000; // clear sa_mask sigemptyset(&this->signalaction.sa_mask); // set sa_siginfo flag utilize extended signal-handler function this->signalaction.sa_flags = sa_siginfo; // define sigaction method // function called signal this->signalaction.sa_sigaction = timer::alarmfunction; // define sigevent // info forwarded signal-handler function memset(&this->signalevent, 0, sizeof(this->signalevent)); // sigev_signal flag there sigev_value this->signalevent.sigev_notify = sigev_signal; // it's possible give pointer object this->signalevent.sigev_value.sival_ptr = (void*) this; // declare signal alarm signal this->signalevent.sigev_signo = sigalrm; // install timer timer_create(clock_realtime, &this->signalevent, &this->timerid); sigaction(sigalrm, &this->signalaction, null); } void start() { // start timer //timer_settime(this->timerid, 0, &this->timerspecs, null); setitimer(itimer_real, &timer_ms, null); return; } static void alarmfunction(int signumb, siginfo_t *si, void *uc) { // pointer out of siginfo construction , asign new pointer variable timer *ptrtimer = reinterpret_cast<timer *> (si->si_value.sival_ptr); // phone call fellow member function ptrtimer->ontimeout(); } private: f ontimeout; }; template<typename f> timer<f> createtimer(int milliseconds, f callback) { homecoming timer<f>(callback, milliseconds); }

note in timer class template f ontimeout called in timer::alarmfunction() method using pointer stored in siginfo_t structure.

static void alarmfunction(int signumb, siginfo_t *si, void *uc) { // pointer out of siginfo construction , asign new pointer variable timer *ptrtimer = reinterpret_cast<timer *> (si->si_value.sival_ptr); // phone call fellow member function ptrtimer->ontimeout(); }

and main.cpp:

#include "timer.h" #include <stdlib.h> #include <iostream> class generic { private: int m_data; public: generic( int info ) : m_data( info ) {} int getdata() { return( m_data); } }; void handletimer() { std::cout << "handletimer " << std::endl; return; } int main(int argc, char *argv[]) { generic obj(42); auto timer = createtimer(1000, [] { handletimer(); }); timer.start(); while(1) { sleep(5); } return( 0 ); }

in main.cpp see created silly little class called generic , instantiated 1 obj.

some questions:

1- how can pass obj handletimer() in line:

auto timer = createtimer(1000, [] { handletimer(); });

so when timer triggered handletimer() called timer class , has access obj?

2- might improve ways this?

i've created much simpler timer class takes frequency , static function parameters when timer expires static function called. nice, static function doesn't have access class scope , has no access user defined info without resorting global data.

edit: i've tried following:

void handletimer( generic *obj ) { std::cout << "handletimer " << std::endl; return; } int main(int argc, char *argv[]) { generic obj(42); auto timer = createtimer(1000, [&obj] { handletimer(&obj); }); timer.start(); while(1) { sleep(5); } return( 0 ); }

but causes segfault. gdb session below:

(gdb) file blink reading symbols /home/jrn/build_root/src/svn/arm/arm-gpio/timer/blink...done. (gdb) run starting program: /home/jrn/build_root/src/svn/arm/arm-gpio/timer/blink [thread debugging using libthread_db enabled] using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". programme received signal sigsegv, segmentation fault. 0x000000000040298a in __lambda0::operator() (__closure=0x100) @ main.cpp:28 28 auto timer = createtimer(1000, [&obj] { handletimer(&obj); }); (gdb)

your code has undefined behavior in @ to the lowest degree 2 different places.

first, createtimer function returns timer object value. means it's making re-create of timer object, , because you're passing this pointer sigevent, after copy, this pointer of timer object in main() different. when callback fires, you'll attempting invoke ontimeout on object destroyed.

you away of time because due re-create elision no re-create made. however, can verify buggy behavior compiling -fno-elide-constructors after prepare other bug.

you can work around not using createtimer(), instead add together next lines main(). i'm not sure of improve way prepare this. demonstrates how pass obj value lambda.

auto l = [obj]() { handletimer(obj); }; timer<decltype(l)> timer(l, 1000); timer.start();

also consider making class non-copyable/assignable

timer(timer const&) = delete; timer& operator=(timer const&) = delete;

the sec problem this pointer, don't know plenty timers you're using figure out you're doing wrong. add together these debug statements code:

// it's possible give pointer object this->signalevent.sigev_value.sival_ptr = static_cast<void *>(this); std::cout << "this: " << << std::endl;

and

timer *ptrtimer = static_cast<timer *> (si->si_value.sival_ptr); std::cout << "sival_ptr: " << si->si_value.sival_ptr << std::endl; // phone call fellow member function // ptrtimer->ontimeout();

you'll see pointer value printed 2 statements different. looking @ code had commented out, , this answer, made next changes:

add info fellow member , initialize in constructor

struct itimerspec timerspecs; ... timerspecs.it_value.tv_sec = milliseconds / 1000; timerspecs.it_value.tv_nsec = ( milliseconds % 1000 ) / 1000; // needs fixing timerspecs.it_interval.tv_sec = milliseconds / 1000; timerspecs.it_interval.tv_nsec = ( milliseconds % 1000 ) / 1000; // needs fixing ... void start() { // start timer timer_settime(this->timerid, 0, &this->timerspecs, null); // setitimer(itimer_real, &timer_ms, null); return; }

also modified handletimer slightly

void handletimer(generic g) { std::cout << "handletimer " << g.getdata() << std::endl; return; }

now code runs , prints

handletimer 42

c++ templates c++11 lambda

Comments

Popular posts from this blog

php - Android app custom user registration and login with cookie using facebook sdk -

django - Access session in user model .save() -

php - .htaccess Multiple Rewrite Rules / Prioritizing -