Z C++ zagadka nr 3
Kompilator zrobi dokładnie to co chcesz. DOKŁADNIE!
i właśnie dlatego trzeba uważać. Ta zagadka jak i pozostałe ma na celu zwrócenie uwagi na miejsca które wydają się oczywiste a moga wprowadzić wiele zamieszania i niepotrzebnych nerwów. W końcu nie od dziś wiadomo że najgroźniejsze błędy znajdują się w „kodzie który napewno jest dobrze”. Tym razem zagadka wymaga trochę więcej od czytelnika, nie wystarczy znajmość C++, trzeba się jeszcze wykazać odrobiną znajomości biblioteki boost.
Na problem oczywiście musiałem trafić na klika godzin przed oddaniem projektu, była godzina 5:14 i nie trudno zgadnąć że odchodził istny eXtreme programming – programowanie gry sieciowej – 2 osoby – 24h. Dojście do tego co jest źle zajęło dobrą godzinę…
Poniższy kod przdstawia 4 najprostsze możliwe przypadki użycia boost::bind w połączeniu z boost::signal, nie różnią się między sobą bardzo:
#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
class Test
{
public:
Test(int x) : x_(x)
{}
void metoda1(int i);
int x_;
};
void Test::metoda1(int i)
{
x_ += i;
}
int main()
{
typedef boost::signal<void (int)> event_sig;
event_sig signal;
Test* t1 = new Test(0);
Test* t2 = new Test(0);
Test t3(0);
Test t4(0);
signal.connect(boost::bind(&Test::metoda1, *t1, _1));
signal.connect(boost::bind(&Test::metoda1, t2, _1));
signal.connect(boost::bind(&Test::metoda1, &t3, _1));
signal.connect(boost::bind(&Test::metoda1, t4, _1));
for(int i = 0; i < 10; ++i)
{
signal(1);
}
std::cout << "t1::x = " << t1->x_ << std::endl;
std::cout << "t2::x = " << t2->x_ << std::endl;
std::cout << "t3::x = " << t3.x_ << std::endl;
std::cout << "t4::x = " << t4.x_ << std::endl;
std::cout << "Powinno(?) byc 10" << std::endl;
}
Mogło by się wydawać że w wyniku, na ekran zostanie wypisana 4 razy liczba 10. Ci bardziej podejrzliwi zaczną się zastanawiać, jaki wpływ mogą mieć te „dodatkowe” symbole dostawione wewnątrz boost::bind. Okazuje się że w przypadkach 1 i 4 ( t1 i t4 ), mimo wysyłania sygnału, wartość pola x_ nie ulega zmianie, natomiast w pozostałych ulega. Dlaczego ?
Rozwiązanie tego problemu jest bardo proste, otóż tworząc binda, biblioteka boost w zależności od sposobu przekazania obiektu na rzecz którego zostanie wywołana metoda, utworzy jego kopię (internal copy) lub będzie operować na przekazanym obiekcie.
Niby proste, ale trzeba mieć świadomość o istnieniu takiego mechanizmu. Nie trudno się „przejechać” na złym przekazaniu obiektu, a tu nie będzie sugestywnego „segmentation fault”….
| Drukuj artykuł | Ten wpis został napisany przez pejotr na 12-06-2009 o 00:40, i jest w kategorii C++, Programowanie. Podążaj za odpowiedziami do tego wpisu przez RSS 2.0. Możesz napisać komentarz, lub trackbacka z Twojej własnej strony. |