Rejestracja na konferencję IGK nr 5

2008-02-05 11:09

Brzydka “maskotka” IGK-5′2008Od wczoraj można już korzystać z internetowej rejestracji uczestników V Ogólnopolskiej Konferencji Inżynierii Gier Komputerowych, która odbędzie się na początku kwietnia. Wprawdzie jak co roku pojawia się mnóstwo pytań i wątpliwości – dodajmy jeszcze, że zwykle tych samych: czy można płacić przelewem elektronicznym, co z noclegiem po ostatnim dniu konferencji, itd. – ale zazwyczaj były one wyjaśniane w odpowiednim czasie przez organizatorów. Miejmy nadzieję, że tak będzie i tym razem :)
Tymczasem zainteresowanych zachęcam do tego, aby nie zrażać się dziwnie wyglądającą “maskotką” konferencji i dokonać rejestracji. Jak wiadomo, ilość miejsc ograniczona ;)

Tags:
Author: Xion, posted under Events » 2 comments

Konstruktory bywają złe

2008-02-04 11:42

Konstruktor to taka dziwna funkcja składowa, która jest wywoływana w trakcie tworzenia obiektu. Jest więc w zasadzie odpowiedzialna za jego przygotowania do użytku, czyli odpowiednią inicjalizację. Tak przynajmniej jest w teorii.
W rzeczywistości jednak konstruktor powinien robić jak najmniej. Jest tak z kilku powodów:

  1. Konstruktor działa na nie w pełni utworzonym obiekcie, co sprawia, że nie zachowuje się on do końca tak, jak inne metody. Najlepszym przykładem jest to, że w konstruktorze nie działają polimorficzne wywołania funkcji wirtualnych dla obiektu, który jest tworzony.
  2. Jeżeli w konstruktorze coś pójdzie źle, i zostanie wyrzucony wyjątek, to destruktor nie zostanie wywołany, aby nasz niekompletny obiekt posprzątać. Jest tak właśnie z tego powodu, że ów obiekt będzie wtedy “niezupełnie skonstruowany”, zaś destruktory w założeniu mają zwalniać tylko w pełni zainicjowane obiekty.
  3. Konstruktory są wywołane w wielu różnych sytuacjach i czasami trudno jest śledzić, kiedy. Do takich sytuacji należą wszelkie instrukcje wprowadzające zmienne należące do danej klasy, konstruktory klas pochodnych, a także konstruktory klas, które zawierają instancje naszej klasy w charakterze pól. Łącznie może być ich całkiem dużo i lepiej upewnić się, że przy okazji są wykonywane tylko te czynności, które są niezbędnie konieczne.

Pewne duże obiekty mogą oczywiście wymagać skomplikowanej inicjalizacji. Wówczas, zamiast pakować całą tę logikę do konstruktora, lepiej jest prawdopodobnie oddzielić inicjalizację od właściwego tworzenia obiektu. W tym celu można go zaopatrzyć w metodę w rodzaju Create czy Load, która dokonuje właściwego przygotowania obiektu do działania.
Może wydawać się to lekkim zawracaniem głowy, ale dla nietrywialnych obiektów ma sens. Pozbywamy się wad wymienionych powyżej, a jednocześnie zyskujemy dodatkowe możliwości (choćby dlatego, że wspomniana metoda może być wirtualna).

Tags: ,
Author: Xion, posted under Programming » 1 comment

‘No i co tu jest źle?’ w wersji książkowej

2008-02-02 17:57

Kiedy ma się dość pokaźną biblioteczkę książek, czasami natrafia się na pozycję, która nie wiadomo skąd się w niej wzięła. Pytanie takie staje się tym bardziej uzasadnione, gdy rzeczoną książkę otworzymy, przekartkujemy i pobieżnie przeglądniemy, by po krótkim czasie uznać, że najchętniej widzielibyśmy ją w… punkcie skupu makulatury :P
Okładka książki “Jak NIE programować w C++”Coś takiego przytrafiło mi się zupełnie niedawno. Książką o której mam taką “pochlebną” opinię, jest dziełko opatrzone tytułem Jak NIE programować w C++. Jeszcze ciekawszy jest chyba podtytuł, który mówi, że wewnątrz znajdziemy dokładnie 111 programów z błędami oraz trzy działające. Statystyka jest imponująca, ale o co tak naprawdę tutaj chodzi?… Autor przedstawia nam mianowicie coś w rodzaju zbioru koderskich zagadek do samodzielnego rozwiązania, które polegają oczywiście na znalezieniu błędu w przedstawionym kawałku kodu.

Jak podejrzewam, celem tej książki w zamyśle autora było ustrzeżenie programistów C++ przez różnego rodzaju typowymi błędami, jakie mogą się zakraść do pisanego przez nich kodu. Cel to chwalebny, chociaż dość utopijny – w końcu nie wystarczy wiedzieć, na czym błąd polega, aby w magiczny sposób już nigdy więcej go nie popełnić. Trochę więcej wątpliwości mam natomiast co do obranej metody. Nie wiem, w jaki sposób obejrzenie ponad stu błędnych kodów ma sprawić, że będziemy częściej pisali poprawny kod. Spodziewałbym się raczej podświadomego nauczenia się prezentowanych tam złych przykładów i ich spontanicznego stosowania w rzeczywistych programach, co raczej nie ułatwiłoby nikomu pracy :)
Byłoby oczywiście świetnie, gdyby przykłady te były jedynymi niepoprawnymi kawałkami kodów, z którymi przychodzi nam się mierzyć. Ale przecież jest to odległe od prawdy o całe lata świetlne. Jako koderzy sami nieuchronnie produkujemy niepoprawny kod, który co rusz musimy korygować. Prawdopodobnie więc nie potrzebujemy dodatkowych łamigłówek tego rodzaju, bo wystarczą nam te, które w nieumyślny sposób tworzymy sami dla siebie. I niestety nie możemy w ich przypadku – w przeciwieństwie do kodów z książki – zajrzeć do części końcowej po wskazówki i odpowiedzi.
Jednak nawet wobec takich mankamentów, prezentowane w książce przykłady mogłyby mieć pewną wartość poznawczą. Rzecz w tym, że naprawdę interesujące zagadki można bez trudu policzyć na palcach obu rąk. Pozostałe są albo pomyłkami aż do bólu klasycznymi (na czele z pomyleniem operatora przypisania i równości w warunku logicznym), albo trywialnymi literówkami, albo świadectwami na – delikatnie mówiąc – niekompletną znajomość języka. (Moim faworytem jest deklaracja int n = 1,000,000;, w założeniu inicjująca zmienną wartością równą milion).

Aż chce się zapytać, czy są w tej książce jakieś cechy pozytywne. Odpowiadam prędko, że jak najbardziej, tyle że mają się one nijak do jej zasadniczej treści. Do każdej zagadki autor dołączył bowiem krótką, zabawną historyjkę “z życia wziętą” lub inny śmieszny tekst – wszystko oczywiście z dziedziny IT. Paradoksalnie więc ta “książka o C++” lepiej sprawdza się jako książka z dowcipami.
Jest też druga dobra strona. Przypomniałem sobie mianowicie, skąd u mnie wzięła się ta dziwna pozycja. Otóż zakupiłem ją podczas jakichś tragów wydawniczych, które akurat odbywały się na uczelni, zapłaciwszy za nią około dziesięć złotych. Nietrudno przeboleć taką niewielką sumę, nawet mimo tego, że nikomu nie poleciłbym wydania na tę książkę nawet jednej złotówki :)

Tags: ,
Author: Xion, posted under Books, Programming » 4 comments

Wypadki chodzą po laptopach

2008-02-01 11:13

Oglądając wczoraj jeden z programów informacyjnych, przeżyłem lekki szok. Oto w jednym z materiałów dziennikarze prezentowali dwa dość ponuro wyglądające laptopy. W jednym na przykład wierzchnia warstwa pokrywy częściowo nie trzymała się reszty obudowy; w drugim zaś przez ekran przebiegała urocza rysa (i to chyba nawet niejedna).
Nie był to bynajmniej reportaż pod tytułem “Dziwne przypadki utraty danych”, a rzeczone komputery nie zostały wcale zebrane z jezdni po bliskim spotkaniu z samochodem ani wyłowione z dna morza. Oba komputery pochodziły z Ministerstwa Sprawiedliwości, a więc miejsca dalekiego od takich ekstremalnych wypadków. A stąd już o krok od wniosku, że uszkodzenia te powstały od normalnego użytkowania komputerów.

I to jest straszne! Pomyślmy tylko, że wyciągamy laptop z torby i nagle zauważamy, że ni z tego, ni z owego, obudowa ekranu wygląda tak, jakby trzymała się tylko na słowo honoru. Albo budzimy się rano i widzimy, że matryca została nie wiadomo dlaczego podzielona na pół mało efektowną rysą. A wszystko to może zdarzyć się zupełnie spontanicznie i bez żadnych wyraźnych powodów! Bo skoro wydarzyło się w tak spokojnym i nudnym miejscu jak zwykłe ministerstwo, podczas całkowicie normalnego i zgodnego ze wszystkimi normami procesu użytkowania, to przecież może zdarzyć się każdemu z nas, prawda?…
Mam aczkolwiek wrażenie, że gdyby rzeczywiście coś takiego kiedyś przytrafiło się mnie albo dowolnemu innemu, przeciętnemu użytkownikowi, to nadal mógłby to być materiał do pokazania w TVN. Tyle że nie w Faktach, a raczej w Nie do wiary ;-)

Tags: ,
Author: Xion, posted under Life, Thoughts » 4 comments

Długo oczekiwane uaktualnienie

2008-01-31 12:38

Niebieskie logo WordPressWersja 2.3 WordPressa pojawiła się już kilkanaście tygodni temu, ale przez bardzo długi czas broniłem się przed uaktualnieniem. Ta wersja ma bowiem sporo zmian w stosunku do poprzedniej, a skutkiem mogła być niekompatybilność niektórych używanych tutaj pluginów i konieczność co najmniej ich uaktualnienia.
Faktycznie nie obyło się bez kilku problemów, ale ostatecznie całą tę operację upgrade‘u mogę chyba uznać za udaną. W każdym widać bez wątpienia, że strona nadal działa :)

Zapewne najważniejszą zmianą serii 2.3.x jest to, że pojawia się wbudowana obsługa tagów, którymi można opatrywać posty. Ale z faktu, że coś takiego istnieje, nie wynika jeszcze, bym miał z tego korzystać ;P Jakoś mam przeczucie, że pojawienie się na stronie przesławnej chmurki tagów wcale nie byłoby posuwaniem się w dobrym kierunku…


Author: Xion, posted under Website » 3 comments

Własny operator rzutowania

2008-01-30 22:27

W C++ nadal można używać "tradycyjnego" rzutowania w postaci (typ)wyrażenie, bo cały czas zachowywana jest przynajmniej częściowa kompatybilność wstecz ze starym C. Jak wiadomo jednak, zaleca się raczej stosowanie nowych (tzn. wprowadzonych w C++; faktycznie są już one raczej stare) operatorów rzutowania, czyli static_cast, dynamic_cast, reinterpet_cast i const_cast. Jest tak między innymi dlatego, iż pozwalają one rozróżnić rzutowania bezpieczne - które można sprawdzić w czasie kompilacji i które zawsze "mają sens" - od pozostałych.
Składnia takiego rzutowania to oczywiście something_cast<typ>(wyrażenie). Jeśli przyjrzymy się jej bliżej, to zauważymy interesującą rzecz. Otóż jest to bardzo podobne do pewnej formy wywołania szablonu funkcji. Ten fakt plus pewne zasady dotyczące dedukcji argumentów takich szablonów sprawiają, że zasadniczo możemy w C++ tworzyć... własne operatory rzutowania.

Prawdopodobnie najbardziej znanym jest implicit_cast, czyli operator rzutowania niejawnego. Możemy go zdefiniować następująco:

template <typename Dest, typename Src>
inline Dest implicit_cast(const Src& arg)
{
   return arg;
}

i wywoływać w bardzo porządny sposób:

string str = implicit_cast<string>("Hello world");

Ze strony swojego dzialania operator ten nie jest specjalnie ciekawy, bo to przykład językowego purytanizmu czystej wody. implicit_cast wykonuje bowiem te konwersje, które kompilator i tak by przeprowadził niejawnie; widać to zresztą po kodzie odpowiadającej mu funkcji.
No właśnie - warto zauważyć, że jest w gruncie rzeczy zwykła funkcja szablonowa. Działa ona jak operator rzutowania, gdyż drugi z argumentów tego szablonu - typ źródłowy - może zostać wydedukowany z argumentu funkcji (czyli wyrażenia, które rzutujemy). Musimy jedynie podać pierwszy z nich, czyli typ docelowy - ale tego można się było spodziewać. Trzeba zaznaczyć, że kolejność obu parametrów szablonu musi być właśnie taka, ponieważ ich przestawienie spowodowałoby, że automatyczna dedukcja nie mogła by zostać przeprowadzona. Zachodzi ona bowiem począwszy od końcowych parametrów.

Prawdopodobnie taki własny operator rzutowania to przede wszystkim efektowna sztuczka. Nic więc dziwnego, że kilka przykładów (np. lexical_cast) jest częścią biblioteki Boost, która niemal w całości jest zbiorem takich językowych gadżetów :) Sam aczkolwiek wymyśliłem dosyć dawno temu operator "rzutowania bezwzględnego", który wygląda mniej więcej tak:

template <typename Dest, typename Src>
inline Dest absolute_cast(const Src& arg)
{
   return *(reinterpret_cast<Dest*>(const_cast<Src*>(&arg)));
}

Służy on do dosłownego rzutowania dowolnego typu na dowolny inny w sensie zmiany interpretacji bajtów. Zdaje się on działać dla większości typów w C++ (głównym wyjątkiem są typy referencyjne, co nie jest specjalną niespodzianką) i bywa całkiem przydatny.

Naturalnie można wymyślić jeszcze sporo innych niestandardowych operatorów rzutowania, jak choćby konwersje między napisami w różnych kodowaniach (ANSI, Unicode) czy do/z jakichś własnych typów, opakowujących klasy zewnętrzne. W każdym razie widać znowu (i pewnie nie ostatni raz), że C++ pozwala nam na bardzo dużo, skoro nawet te nieco rozwlekłe *_casty można jakoś oswoić do własnych potrzeb :]

Tags: , ,
Author: Xion, posted under Programming » Add comment

Wektor prostopadły do danego

2008-01-29 17:46

Wektor wyznacza pewną linią na płaszczyźnie lub w przestrzeni. A skoro tak jest, to czasami możemy potrzebować wektora, który będzie prostopadły do jakiegoś innego, który jest nam znany. Wyznaczenie go nie jest specjalnie trudne, ale w zależności od tego, czy wszystko dzieje się w 2D czy 3D, trzeba uwzględnić pewne szczegóły.
Takim szczegółem na pewno nie jest jednak długość wynikowego wektora, bo możemy go przecież zawsze przeskalować do żądanego rozmiaru. W tym celu wystarczy go najpierw znormalizować (podzielić przez aktualną długość), a potem pomnożyć przez nową długość.

Wektory prostopadłe na płaszczyźnieNa płaszczyźnie wektor prostopadły jest wyznaczony w miarę jednoznacznie:

const VEC2 Orthogonal(const VEC2& v)
{
   return VEC2(-v.y, v.x);
}

Mówiąc ściślej, znany jest jego kierunek, a przy ustalonej długości może mieć jedynie dwa ustalone, przeciwne zwroty. To w zasadzie dość oczywiste: prostą prostopadłą do wektora wyznaczyć jest... prosto (;D), natomiast kwestia jej skierowania zależy już od nas.
Dla wektora [x, y] prostopadłymi do niego będą więc wektory [-y, x] i [y, -x].

W przestrzeni trójwymiarowej jedno-(a właściwie dwu-)znacznie można wyznaczyć jedynie wektor prostopadły do dwóch innych. Oczywiście w takim przypadku tworzą one płaszczyznę, więc tak naprawdę poszukujemy wektora (prostej), przecinającego pod kątem prostym tę właśnie płaszczyznę. Jak wiadomo, można to uczynić, obliczając iloczyn wektorowy (cross product) tych dwóch wektorów.
W przypadku, gdy mamy tylko jeden wektor, musimy się rzecz jasna liczyć z tym, że kierunków prostopadłych do niego jest nieskończenie wiele. Dlatego możliwe jest co najwyżej wyznaczenie dowolnego z nich, co jednak czasami jest zadowalające. (Możemy mieć np. płaszczyznę wyznaczoną przez punkt i normalną; jeżeli chcemy otrzymać wektor leżący na tej płaszczyźnie, musimy znaleźć wektor prostopadły do normalnej). Aby tego dokonać, trzeba po prostu dobrać drugi wektor do iloczynu. Jedynym wymaganiem dla niego jest to, aby nie był on równoległy z pierwszym:

const VEC3 AnyOrthogonal(const VEC3& v)
{
   if (!Equal(v.x, v.y) || !Equal(v.y, v.z))
      // cross z permutacją składowych
      return Cross(v, VEC3(v.z, v.x, v.y));
   else
      // cross z wersorem osi X
      return Cross(v, VEC3(1.0f, 0.0f, 0.0f));
}

W celu wybrania drugiego argumentu możemy zastosować powyższą sztuczkę. Zamieniamy po prostu składowe pierwotnego wektora tak, aby żadna nie była na swoim miejscu - tutaj dla wektora [x, y, z] taką permutacją jest np. [z, x, y]. Taki wektor prawie na pewno nie będzie równoległy z pierwowzorem.
Wiemy jednak, że prawie robi wielką różnicę :) Problematyczne są te wektory, których wszystkie trzy elementy mają taką samą wartość. Musimy więc sprawdzić ten przypadek. Zamiast permutacji można wtedy zastosować chociażby wektor równoległy do którejś z osi układu współrzędnych.

Tags:
Author: Xion, posted under Uncategorized » 5 comments
 


© 2012 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.