-
Notifications
You must be signed in to change notification settings - Fork 82
Fix multi-signal emission in case of fused functor data source callbacks #293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
619fce2
41cd372
f6f11f6
8850590
a5857b2
ca0c42b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,27 +64,29 @@ namespace RTT | |
template<class T> | ||
struct AStore | ||
{ | ||
typedef T arg_type; | ||
T arg; | ||
AStore() : arg() {} | ||
AStore(T t) : arg(t) {} | ||
AStore(AStore const& o) : arg(o.arg) {} | ||
|
||
T& get() { return arg; } | ||
void operator()(T a) { arg = a; } | ||
operator T() { return arg;} | ||
operator T&() { return arg; } | ||
}; | ||
|
||
template<class T> | ||
struct AStore<T&> | ||
{ | ||
typedef T& arg_type; | ||
T* arg; | ||
AStore() : arg( &NA<T&>::na() ) {} | ||
AStore(T& t) : arg(&t) {} | ||
AStore(AStore const& o) : arg(o.arg) {} | ||
|
||
T& get() { return *arg; } | ||
void operator()(T& a) { arg = &a; } | ||
operator T&() { return *arg;} | ||
operator T&() { return *arg; } | ||
}; | ||
|
||
template<class T> | ||
|
@@ -287,7 +289,7 @@ namespace RTT | |
typename Signal<ToBind>::shared_ptr msig; | ||
#endif | ||
|
||
BindStorageImpl() : vStore(boost::ref(retv)) {} | ||
BindStorageImpl() : vStore(retv) {} | ||
BindStorageImpl(const BindStorageImpl& orig) : mmeth(orig.mmeth), vStore(retv) | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
, msig(orig.msig) | ||
|
@@ -335,10 +337,10 @@ namespace RTT | |
void store(arg1_type t1) { a1(t1); } | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get()); | ||
if (msig) (*msig)(a1); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind(mmeth, boost::ref(a1.get()) ) ); | ||
retv.exec( boost::bind(mmeth, a1 ) ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be checked: Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like boost::bind is always copying the arguments itself, and only invokes the conversion operator at the time the functor is actually called: https://stackoverflow.com/questions/11255144/why-does-boostbind-store-arguments-of-the-type-passed-in-rather-than-of-the-ty In this case the patch in a5857b2 (this PR) and a2ccd79 (in |
||
else | ||
retv.executed = true; | ||
} | ||
|
@@ -375,10 +377,10 @@ namespace RTT | |
void store(arg1_type t1, arg2_type t2) { a1(t1); a2(t2); } | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get(), a2.get()); | ||
if (msig) (*msig)(a1, a2); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind(mmeth, boost::ref(a1.get()), boost::ref(a2.get()) ) ); | ||
retv.exec( boost::bind(mmeth, a1, a2 ) ); | ||
else | ||
retv.executed = true; | ||
} | ||
|
@@ -417,10 +419,10 @@ namespace RTT | |
void store(arg1_type t1, arg2_type t2, arg3_type t3) { a1(t1); a2(t2); a3(t3); } | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get(), a2.get(), a3.get()); | ||
if (msig) (*msig)(a1, a2, a3); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind(mmeth, boost::ref(a1.get()), boost::ref(a2.get()), boost::ref(a3.get()) ) ); | ||
retv.exec( boost::bind(mmeth, a1, a2, a3 ) ); | ||
else | ||
retv.executed = true; | ||
} | ||
|
@@ -460,10 +462,10 @@ namespace RTT | |
void store(arg1_type t1, arg2_type t2, arg3_type t3, arg4_type t4) { a1(t1); a2(t2); a3(t3); a4(t4); } | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get(), a2.get(), a3.get(), a4.get()); | ||
if (msig) (*msig)(a1, a2, a3, a4); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind( mmeth, boost::ref(a1.get()), boost::ref(a2.get()), boost::ref(a3.get()), boost::ref(a4.get()) ) ); | ||
retv.exec( boost::bind( mmeth, a1, a2, a3, a4 ) ); | ||
else | ||
retv.executed = true; | ||
} | ||
|
@@ -505,10 +507,10 @@ namespace RTT | |
void store(arg1_type t1, arg2_type t2, arg3_type t3, arg4_type t4, arg5_type t5) { a1(t1); a2(t2); a3(t3); a4(t4); a5(t5);} | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get(), a2.get(), a3.get(), a4.get(), a5.get()); | ||
if (msig) (*msig)(a1, a2, a3, a4, a5); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind( mmeth, boost::ref(a1.get()), boost::ref(a2.get()), boost::ref(a3.get()), boost::ref(a4.get()), boost::ref(a5.get()) ) ); | ||
retv.exec( boost::bind( mmeth, a1, a2, a3, a4, a5 ) ); | ||
else | ||
retv.executed = true; | ||
} | ||
|
@@ -552,10 +554,10 @@ namespace RTT | |
void store(arg1_type t1, arg2_type t2, arg3_type t3, arg4_type t4, arg5_type t5, arg6_type t6) { a1(t1); a2(t2); a3(t3); a4(t4); a5(t5); a6(t6);} | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get(), a2.get(), a3.get(), a4.get(), a5.get(), a6.get()); | ||
if (msig) (*msig)(a1, a2, a3, a4, a5, a6); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind( mmeth, boost::ref(a1.get()), boost::ref(a2.get()), boost::ref(a3.get()), boost::ref(a4.get()), boost::ref(a5.get()), boost::ref(a6.get()) ) ); | ||
retv.exec( boost::bind( mmeth, a1, a2, a3, a4, a5, a6 ) ); | ||
else | ||
retv.executed = true; | ||
} | ||
|
@@ -601,10 +603,10 @@ namespace RTT | |
void store(arg1_type t1, arg2_type t2, arg3_type t3, arg4_type t4, arg5_type t5, arg6_type t6, arg7_type t7) { a1(t1); a2(t2); a3(t3); a4(t4); a5(t5); a6(t6); a7(t7);} | ||
void exec() { | ||
#ifdef ORO_SIGNALLING_OPERATIONS | ||
if (msig) (*msig)(a1.get(), a2.get(), a3.get(), a4.get(), a5.get(), a6.get(), a7.get()); | ||
if (msig) (*msig)(a1, a2, a3, a4, a5, a6, a7); | ||
#endif | ||
if (mmeth) | ||
retv.exec( boost::bind( mmeth, boost::ref(a1.get()), boost::ref(a2.get()), boost::ref(a3.get()), boost::ref(a4.get()), boost::ref(a5.get()), boost::ref(a6.get()), boost::ref(a7.get()) ) ); | ||
retv.exec( boost::bind( mmeth, a1, a2, a3, a4, a5, a6, a7 ) ); | ||
else | ||
retv.executed = true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@psoetens Was there a good reason why the operator did not return a reference in the original code? I think not: The object is already copied at least once when creating the
AStore<T>
instance or viaoperator()(T a)
. So no reason to copy it again to read it. For references we use the specialization below instead.Even without the reference return type the object was not copied for the actual operation call because before this patch
.get()
was used to access it inBindStorageImpl<ToBind>
below.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember that I tested this code with objects which did a cout in a copy constructor to count the number of copies made, and then introduced references to reduce the number of copies. That said, I don't remember if there was a formal place in the architecture where a copy 'must' be made, but the AStore seems to be the best place to do it, if required. AStore was meant to mimic the classical C++ function argument behavior.