Beginner question: Why boost::signal creates another instance of the slot object ?
Hi,
I am running the program below (Vista with boost 1.43, mingw/gcc 4.5.1).
I would expect slot.x to be 5 but it is zero.
Why boost::signal creates another instance of the slot object ?
What am I missing here ?
Thank you in advance for your attention,
Mau.
----------------------------------------------------------------
#include <iostream>
#include
AMDG Mauricio Gomes wrote:
I am running the program below (Vista with boost 1.43, mingw/gcc 4.5.1).
I would expect slot.x to be 5 but it is zero.
Why boost::signal creates another instance of the slot object ? What am I missing here ?
boost::signal stores a copy of the function object. If you don't want to make a copy use boost::ref. sig.connect(boost::ref(f)); If you do this, you need to be careful that the function object doesn't go out of scope too soon. In Christ, Steven Watanabe
Thank you very much Steven, boost::ref worked fine.
Just for my education, what is the rationale behind making a copy of
the signaled object ?
It seems odd to me since the object interested in receiving the event
ends up not receiving it (unless we use boost::ref).
I am obviously missing something conceptually here. If you or anyone
could explain it to me I'd really appreciate.
Thanks again.
Mau.
2010/8/19 Steven Watanabe
AMDG
Mauricio Gomes wrote:
I am running the program below (Vista with boost 1.43, mingw/gcc 4.5.1).
I would expect slot.x to be 5 but it is zero.
Why boost::signal creates another instance of the slot object ? What am I missing here ?
boost::signal stores a copy of the function object. If you don't want to make a copy use boost::ref.
sig.connect(boost::ref(f));
If you do this, you need to be careful that the function object doesn't go out of scope too soon.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- Mau
AMDG Mauricio Gomes wrote:
Thank you very much Steven, boost::ref worked fine.
Just for my education, what is the rationale behind making a copy of the signaled object ? It seems odd to me since the object interested in receiving the event ends up not receiving it (unless we use boost::ref).
Passing function objects by value is the normal convention in C++. There are many cases where it is the correct behavior. For example, if you you connect a function object created by boost::bind to the signal, the function object is a temporary and is destroyed immediately. If it were stored by reference, the boost::signal would be left with an invalid reference. Don't think of the function object as the object receiving the signal. The function object is an action to be performed.
I am obviously missing something conceptually here. If you or anyone could explain it to me I'd really appreciate.
In Christ, Steven Watanabe
AMDG On Thu, Aug 19, 2010 at 05:29:20PM -0700, Steven Watanabe wrote:
AMDG
Mauricio Gomes wrote:
Just for my education, what is the rationale behind making a copy of the signaled object ? It seems odd to me since the object interested in receiving the event ends up not receiving it (unless we use boost::ref).
Passing function objects by value is the normal convention in C++. There are many cases where it is the correct behavior. For example, if you you connect a function object created by boost::bind to the signal, the function object is a temporary and is destroyed immediately. If it were stored by reference, the boost::signal would be left with an invalid reference. Don't think of the function object as the object receiving the signal. The function object is an action to be performed.
I am obviously missing something conceptually here. If you or anyone could explain it to me I'd really appreciate.
As Steven outlines, if you have a callable in C++, you should expect it to be copied, a lot. As such, you should make it lightweight and cheap to copy, preferably holding any shared state with shared_ptrs or weak_ptrs, or if lifetimes are known to exceed the lifetime of the callable, by reference or reference_wrapper. It's awfully hard to hold on to something by reference for a longer period, as that unnecessarily puts the onus on the caller to ensure that an unknown lifetime is guaranteed. As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable. It's normally good form to make things that should not be copied boost::noncopyable or otherwise artificially restricted from copying, in order to catch such assumptions at an early stage instead of through runtime bugs. -- Lars Viklund | zao@acc.umu.se
Hi, I am still digesting the information. I understand the problem with lifetime management but when I do: sig.connect(x); and x being the listener, I would expect x to be called, not another instance of X. I will study more what you guys have explained. I hope at some point it will click on my mind. :)
As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable I thought the compiler would generate a copy constructor and assignment operator suitable for S. Is not the case ?
struct S
{
int x;
S (): x(0) {}
void operator () (int i)
{
std::cout << "&slot1 = " << this << std::endl;
x = i;
std::cout << "slot1.x = " << this->x << std::endl;
}
};
Thank you !
2010/8/20 Lars Viklund
AMDG
As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable.
It's normally good form to make things that should not be copied boost::noncopyable or otherwise artificially restricted from copying, in order to catch such assumptions at an early stage instead of through runtime bugs.
-- Lars Viklund | zao@acc.umu.se _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- Mau
On Fri, Aug 20, 2010 at 04:25:07PM -0300, Mauricio Gomes wrote:
As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable I thought the compiler would generate a copy constructor and assignment operator suitable for S. Is not the case ? -- Mau
The synthesised cctor and op= will do a member-wise copy and assignment, respectively. If you have value members, the copy or target will contain copies of them. If you want to share state between two instances, you need to have reference members, reference_wrapper members or pointer-type members. Like say: struct S1 { shared_ptr<int> x; }; or struct S2 { boost::reference_wrapper<int> x; }; -- Lars Viklund | zao@acc.umu.se
The problem was my interpretation of what you meant by "properly copyable".
Thanks Lars.
2010/8/20 Lars Viklund
On Fri, Aug 20, 2010 at 04:25:07PM -0300, Mauricio Gomes wrote:
As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable I thought the compiler would generate a copy constructor and assignment operator suitable for S. Is not the case ? -- Mau
The synthesised cctor and op= will do a member-wise copy and assignment, respectively.
If you have value members, the copy or target will contain copies of them.
If you want to share state between two instances, you need to have reference members, reference_wrapper members or pointer-type members.
Like say:
struct S1 { shared_ptr<int> x; };
or
struct S2 { boost::reference_wrapper<int> x; };
-- Lars Viklund | zao@acc.umu.se _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- Mau
On Fri, Aug 20, 2010 at 1:25 PM, Mauricio Gomes
Hi,
I am still digesting the information. I understand the problem with lifetime management but when I do:
sig.connect(x);
and x being the listener, I would expect x to be called, not another instance of X. I will study more what you guys have explained. I hope at some point it will click on my mind. :)
Think of it this way, what connect accepts is a callable, not an
instance of an object or anything like that.
A callable *will* be copied, potentially many times.
Your object instance fulfills the needed parts of callable, but its
logic is improperly defined as it does not handle 'many' copies, hence
it fails at the overall concept.
Need to wrap it in another callable that does implement the callable
concept properly, such as boost::ref or boost::bind or whatever other
dozen things or custom things.
Remember this, you are not connecting an object/instance, you are
connecting an action, most tutorials/examples/etc... show off an
action using boost::bind, which is fully callable, to an action of an
object/instance.
On Fri, Aug 20, 2010 at 1:25 PM, Mauricio Gomes
As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable I thought the compiler would generate a copy constructor and assignment operator suitable for S. Is not the case ?
struct S { int x;
S (): x(0) {}
void operator () (int i) { std::cout << "&slot1 = " << this << std::endl; x = i; std::cout << "slot1.x = " << this->x << std::endl; } };
Thank you !
2010/8/20 Lars Viklund
: AMDG
As for your initial problem of the receiver being dis-associated from the callable, it's probably because it's not properly copyable.
It's normally good form to make things that should not be copied boost::noncopyable or otherwise artificially restricted from copying, in order to catch such assumptions at an early stage instead of through runtime bugs.
-- Lars Viklund | zao@acc.umu.se _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- Mau _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (4)
-
Lars Viklund
-
Mauricio Gomes
-
OvermindDL1
-
Steven Watanabe