[signals] calling delete member on connect?
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Ok, am I wrong in assuming this shouldn't be happening on my linux box? [gcc 4.0.2][boost 103200] First the test program, then the output: #include <iostream> #include <cstdlib> #include <boost/signals.hpp> using namespace std; using namespace boost; class tst_out{ public: void operator()() const{ cout << "test out data1" << endl;} ~tst_out(){ cout << "Called del for tst_out" << endl;} }; class tst_out2{ public: void operator()() const{ cout << "test out 2" << endl;} ~tst_out2(){ cout << "Called del for tst_out2" << endl;} }; signal<void ()> sig; int main(int argc, char *argv[]) { tst_out tst1; tst_out2 tst2; sig.connect(tst1); sig.connect(tst2); sig(); cout << "exiting program" << endl; return EXIT_SUCCESS; } Now the output: Called del for tst_out Called del for tst_out Called del for tst_out Called del for tst_out Called del for tst_out Called del for tst_out Called del for tst_out Called del for tst_out2 Called del for tst_out2 Called del for tst_out2 Called del for tst_out2 Called del for tst_out2 Called del for tst_out2 Called del for tst_out2 test out data1 test out 2 exiting program Called del for tst_out2 Called del for tst_out Called del for tst_out Called del for tst_out2 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFD5RS4pxCQXwV2bJARAkBzAJ9mSmfH79X/IaOlmlquUMk9Ww/dAgCdH9xz /BaVLQC9shMvnYxBPMv13DU= =jU/r -----END PGP SIGNATURE-----
Evan Carew wrote:
Ok, am I wrong in assuming this shouldn't be happening on my linux box? [gcc 4.0.2][boost 103200]
Yes, you are most likely wrong. Since the test objects are stateless, they are probably passed by value inside the library, which means that temporaries get constructed and destructed. Each temporary destruction prints a message. Sebastian Redl
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Sebastian Redl wrote:
Evan Carew wrote:
Ok, am I wrong in assuming this shouldn't be happening on my linux box? [gcc 4.0.2][boost 103200]
Yes, you are most likely wrong. Since the test objects are stateless, they are probably passed by value inside the library, which means that temporaries get constructed and destructed. Each temporary destruction prints a message.
Sebastian Redl
So is there a fix for this? -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFD5hNZpxCQXwV2bJARApzFAKCfVkjk1+feYtoYX7QjC8bBsH6m0ACfbXTE 9Xx4M+mMnX7LWdY6pE8lEUY= =07/c -----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Sebastian Redl wrote:
Evan Carew wrote:
Ok, am I wrong in assuming this shouldn't be happening on my linux box? [gcc 4.0.2][boost 103200]
Yes, you are most likely wrong. Since the test objects are stateless, they are probably passed by value inside the library, which means that temporaries get constructed and destructed. Each temporary destruction prints a message.
Sebastian Redl
Hmm, have you even used signals before? The manual for it was the basis of my example program. I don't think you would have said that if you had used the library before. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFD5hYopxCQXwV2bJARAq+eAKCzaLapKFeL4OQrcd9FC+7NSWT8yACeOMNA DbmxCN4RMONsdh2xezwx/24= =LaSf -----END PGP SIGNATURE-----
Evan Carew wrote:
Hmm, have you even used signals before? The manual for it was the basis of my example program. I don't think you would have said that if you had used the library before.
Which part of the manual? I have used Signals before, but I admit that I've never been in a situation where the destructor of my signal would have been relevant. Nevertheless, I'm very curious as to what prompted you to assume that I haven't used the library. I'm browsing the docs right now, and there is hardly any mention of what happens with the slot object, beyond that it's passed to connect() by const reference. This does not, however, mean that it is stored internally as a reference. In fact, since the const reference allows you to pass a temporary, such behaviour would be catastrophic. The first block of the design overview, "Type Erasure", hints that Signals stores the slot objects as Boost.Function objects. So let's go to that library's documentation and see what they have to say on the matter. Boost.Function says, in the documentation of functionN::functionN(F):
*Postconditions*: |*this| targets a copy of |f| if |f| is nonempty, or |this->empty <http://www.cppdoc.local/boost/doc/html/functionN.html#id1001382-bb>()| if |f| is empty.
In other words, the object is copied into the Function, not referenced. The tutorial also states that if you wish that no copying is done, you should use boost::ref or boost::cref to wrap the object. Internally, Signals will then proceed to store the function object somewhere. It is not unreasonable to assume that four temporary copies of the Function object are created. And as functionN::functionN(const functionN&) states:
*Postconditions*: Contains a copy of the |f|'s target, if it has one, or is empty if |f.empty <http://www.cppdoc.local/boost/doc/html/functionN.html#id1001382-bb>()|
Again a copy of your own object will be created. Thus, when temporary Function objects get created, temporaries of your type are also created. And destructed again, calling the destructor of your object. (On a side note, I would recommend against calling it the "delete function". Delete has a very specific meaning in C++, and while it has something to do with destructors, it's still something entirely different.) So, on to the solution of your problem that you asked for in the other mail. Solution 1) Don't depend on the destructor of your slot object. Slot objects should be largely trivial. I would recommend this solution. Solution 2) If you really HAVE to depend on the destructor (say, because for some reason you have a big, stateful slot object), you can follow Function's tutorial and wrap the object in a boost::ref or boost::cref. Sebastian Redl
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Sebastian, Thanks for the more detailed reply. I apologize for my earlier response to your first message as it sounded distinctly like one of those pedantic lurkers I run into on the C++ news group from time to time. Usually, when I find one, I simply put them into my TB filters list. As you may have guessed, my question was about how to make a (to me) realistic example of the signals library work. The overly simplistic hello example in the manual is where I stopped, having thought the signals library was truly easy to use. Much to my surprise, when it came time to actually put it to use in my application, I got all kinds of strange seg fault errors. After spending an hour or so I didn't have to spare on figuring out where the problem was emanating from, I'll admit to being a little surprised and frustrated (maybe even a little angry) as the hello example didn't seem to do a good job of warning the user that all but the most trivial examples of that use of the library would work as designed. I suspect like most programmers in my position, time is a luxury we can hardly afford to spare giving every dense manual of a library we are looking at a close read, not to mention slogging through the source code. Previous to my getting more involved with the boost libraries, I have made heavy use of the STL. Except for the generous SGI site and non-free texts on the subject, there are precious few references on the STL, but that's OK as it is relatively easy to read through the well documented source and figure out what is going on. To some extent, that model of support is broken in boost as the level of complexity has increased. Therefore, people like myself are at the mercy of polite, helpful people like yourself who have already had experience with the library or who had a hand in creating it. Sincerely, Evan Carew P.S. For the archives, the attached code is a working copy of the test code I was trying to implement, compliments to Sebastian Redl and Scott Collins http://scottcollins.net/articles/a-deeper-look-at-signals-and-slots.html using namespace std; using namespace boost; class tst_out{ public: boost::signal<void()>timer; ~tst_out(){ cout << "Called del for tst_out" << endl;} }; class tst_out2{ public: void print(){ cout << "test out 2" << endl;} ~tst_out2(){ cout << "Called del for tst_out2" << endl;} }; int main(int argc, char *argv[]) { tst_out tst1; tst_out2 tst2; tst1.timer.connect(boost::bind(&tst_out2::print, &tst2)); tst1.timer(); cout << "exiting program" << endl; return EXIT_SUCCESS; } -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFD5qzQpxCQXwV2bJARAj1+AKDCSHtkkt8TdA6Z3l4OwMAVpTPEYgCeOE+A epo6b9x3BjEoHiVVNoU7S3Y= =3rjg -----END PGP SIGNATURE-----
participants (2)
-
Evan Carew
-
Sebastian Redl