Taki dzień jak dziś zdarza się nieczęsto, bo przecież średnio (niemal) raz na cztery lata. Ci, którzy mieli okazję się tego dnia urodzić, mogą być z tego albo niezadowoleni – bo mają urodziny cztery razy rzadziej – albo bardzo szczęśliwi: w końcu przecież starzeją się cztery razy wolniej ;-) Wszyscy inni mogą zaś skorzystać z okazji, jaką daje to nieczęste wydarzenie. Jest to mianowicie dobry pretekst, by zastanowić się, co robiliśmy poprzedniego 29 lutego i co być może będziemy robili, gdy taka data zdarzy się po raz kolejny.
Jak to było ze mną? Otóż cztery lata temu byłem ledwie co uczniem drugiej klasy szkoły średniej. Kiedy o tym myślę, widzę, jak nieprawdopodobnie dużo zmieniło się od tego czasu.
Bardzo zmienił się też Warsztat, z którym już wtedy jednak byłem bardzo związany (choćby poprzez pełnienie różnych funkcji względem serwisu, forum czy kanału IRC). Wystarczy przypomnieć, że wtedy większość członków tego community nie znała się osobiście. Zmienić miała to dopiero I Ogólnopolska Konferencja Twórców Gier Komputerowych, która odbyła się ostatecznie parę miesięcy później.
A teraz? Jestem już całkiem dobrze zaprawionym w bojach studentem trzeciego roku informatyki, a wspomniana konferencja za parę tygodni doczeka się już swojej piątej edycji. Warsztat już dawno nie jest tym samym Warsztatem i choć przeżył wiele zmian, nie wszystkie były na szczęście zmianami na gorsze :)
Co będzie za kolejnych lat cztery?… Nie podejrzewam siebie o żadne nadzwyczajne zdolności profetyczne, więc pozwolę sobie nie podejmować żadnych prób wróżenia “z fusów”. Zresztą, na ów rok 2012 zapowiedziano już całkiem sporo wydarzeń – od Mistrzostw Europy w Polsce po koniec świata włącznie – zatem na pewno jest na co czekać ;] Ale i tak wiadomo, że swoją własną przyszłość musimy ułożyć sobie sami…
Fakt jest oczywisty: moderatorzy są tylko ludźmi i mogą popełniać błędy. Dotyczy to nawet tak wybitnych osobistości, jak moderatorzy forum Warsztatu :) Co więcej, można mylić się na całego i globalnie – czyli na przykład w tak fundamentalnej kwestii jak to, czy wobec tzw. lamerstwa przyjmować postawę ostrą czy względnie łagodną.
Można to jednak zawsze poprawić. Ale sytuacja wygląda o wiele gorzej, jeśli moderatorzy przestają działać jako drużyna i zaczynają wchodzić sobie nawzajem w drogę.
W ten sposób dorobiliśmy na Warsztacie dwóch swego rodzaju “frakcji” moderatorskich. Pierwsza z nich opowiada się za literalnym stosowaniem dość restrykcyjnego regulaminu i stanowczym reagowaniem na wszelkie przejawy wspomnianego już lamerstwa. Druga zaś preferuje raczej łagodne podejście do problemu i służenie pomocą nowo przybyłym, którzy niekoniecznie potrafią jeszcze dostosować się do panujących zasad,
Nietrudno zauważyć, że te dwie grupy mogą często wykonywać sprzeczne ze sobą działania. A to na pewno nie poprawia skuteczności ani jednej, ani drugiej. Dodajmy do tego jeszcze spore grono zwolenników każdej z tych opcji wśród zwykłych użytkowników forum i mamy niewielki chaos.
Poglądowa ilustracja, obrazująca dwa różne podejścia do problemu lamerstwa :)
Nie twierdzę oczywiście, że wśród moderatorów nie mogą występować nawet najmniejsze różnice opinii, bo taki stan rzeczy jest z założenia idealny i niemożliwy do osiągnięcia w rzeczywistości. Według mnie wypadałoby jednak prezentować w miarę spójne stanowisko przynajmniej “na zewnątrz”. W sytuacji, gdy dwie grupy wykonują względem siebie mniej lub bardziej krecią robotę, utrzymanie porządku staje się o wiele trudniejsze. A poza tym przysparza to jeszcze większych dylematów tym moderatorom, którzy chcą zachować jako taką ‘neutralność’, do których to zaliczam swoją skromną osobę :]
Modyfikator static
ma w C++ kilka różnych funkcji, a jedną z nich jest deklarowanie składników statycznych w klasach. Jak doskonale wiadomo taki składnik jest wspólny dla wszystkich obiektów tejże klasy i można go używać nawet, jeśli takie obiekty w ogóle nie istnieją.
Zwykle nie ma większych problemów ze statycznymi metodami, natomiast w przypadku pól sprawa często potrafi się skomplikować. Zwłaszcza, że statyczne elementy zmienne i stałe deklarujemy nieco inaczej…
Przede wszystkim należy pamiętać, że statyczne zmienne są właściwie pewnym rodzajem zmiennych globalnych, różniącym się prawie wyłącznie pod względem składniowym. A w przypadku zmiennych globalnych (deklarowanych w nagłówkach poprzez extern
) konieczne jest ich przypisanie do jakiegoś modułu kodu, czyli pliku .cpp. Dzięki temu linker może potem powiązać odwołania do tej zmiennej z nią samą niezależnie od miejsca jej użycia.
To samo dotyczy statycznych pól:
Jest jednak drobna różnica między statycznymi stałymi a zmiennymi polami. W tym drugim przypadku możemy zmiennej nadać początkową wartość; robimy to już w pliku .cpp przy jej definicji – tak jak powyżej. Zrobienie tego od razu w deklaracji jest niedopuszczalne.
Natomiast dla stałych wartość podać musimy i zwykle czynimy to dla odmiany właśnie w pliku nagłówkowym, jeszcze wewnątrz bloku class
:
Wówczas z kolei nie możemy wręcz inicjalizować stałej ponownie w pliku .cpp!
Dość dziwne, prawda? Ale w miarę łatwo to wyjaśnić. Otóż stała ma, jak sama nazwa wskazuje stałą wartość. Dzięki temu, że jest podana w nagłówku, kompilator może zoptymalizować każde miejsce jej normalnego użycia. Zamiast odwoływania się do pamięci, wpisze po prostu wartość stałej “na sztywno” w kodzie wynikowym. Będzie więc to podobne do działania #define
.
Tym niemniej jest to pewna niedogodność, jeśli statyczne stałe i statyczne zmienne definiuje się inaczej. Ale przecież to nie jedyna dziwna cecha C++, która sprawia, że tak ten język lubimy ;-)
Pamięć kodera (ta w hipokampie, nie RAM) jest oczywiście doskonała, ale w większości wypadków także ulotna i mało pojemna. Zaglądanie do dokumentacji w poszukiwaniu każdego drobiazgu jest zaś męczące i mało efektywne. O grubych książkach, które wymagają wertowania spisu treści lub indeksu, już w ogóle nie wspominam.
Stąd np. leksykony O’Reilly, wydawane w Polsce przez Helion oraz Tablice informatyczne tego samego wydawnictwa. Zwłaszcza ten drugi pomysł jest interesujący…
Jego praktyczną (i darmową) realizację znalazłem na stronie pod zaiste wiele mówiącą nazwą AddedBytes.com (dawniej: ILoveJackDaniels.com :)). Tam też można zaopatrzyć się w przydatne tablice zwane cheat sheets.
Jest ich tam całkiem sporo, a po wydrukowaniu mogą być cenną pomocą naukową. Właściwie jedyną ich wadą jest to, że dotyczą tylko technologii webowych: HTML, CSS, PHP, i tak dalej. Tym niemniej mogą być użyteczne choćby jako wzorzec do skonstruowania swoich własnych ściągawek dla bardziej przydatnych koderom narzędzi, jak C++, DirectX, HLSL czy .NET.
Tylko kto odważny się tego podejmie?… ;-)
Oto odwieczny dylemat programistów C/C++: jak deklarować wskaźniki? A dokładniej: w którym miejscu umieścić gwiazdkę? Wybór dotyczy dwóch wariantów składniowych:
Dla kompilatora są one oczywiście równoważne, jednak zwolennicy każdego z nich potrafią podać całe mnóstwo argumentów za jednym i przeciwko drugiemu. I tak: przyklejanie gwiazdki do typu docelowego wskaźnika (tutaj int
) jest popierane tym, że jest ona częścią typu wskaźnikowego (czyli int*
). Z drugiej strony kruczkiem jest, iż deklaracja:
tworzy wskaźnik a
oraz zwykłą zmienną b
– co stanowi argument na rzecz przyklejenia gwiazdki jednak do nazwy zmiennej.
Czy to więc kwestia gustu? Być może. Ja osobiście preferuję styl int* p1;
, a ostatnio odnalazłem jeszcze jeden argument, który może za tym przemawiać. Jeśli bowiem oprócz zadeklarowania wskaźnika zechcemy go też zainicjalizować:
to w konwencji int *p2;
wygląda to na pierwszy rzut oka dość dziwnie. Zgodnie z interpretacją “*p
jest int
em” wychodzi bowiem także na to, iż “inicjalizujemy *p
zerem”. Można więc pomyśleć – zwłaszcza przy mniejszym doświadczeniu w programowaniu w C/C++ – że inicjujemy nie sam wskaźnik, lecz wartość, na którą on wskazuje. To rzecz jasna nieprawda; nadal inicjowany jest wskaźnik, otrzymuje on swój początkowy adres.
Wytrawni koderzy nie popełniliby naturalnie takiej pomyłki. Pamiętajmy jednak, że dobrze napisany kod powinien wymagać możliwie najmniej zastanowienia nad sprawami nieistotnymi. A znaczenie powyższej konstrukcji wydaje się właśnie taką nieistotną sprawą.
POSIX (Portable Operating System Interface) to taki śmieszny “standard dla systemów operacyjnych”, opracowany przez znane skądinąd konsorcjum IEEE. Celem jego stworzenia było zapewnienie jak największej zgodności w działaniu (lub niedziałaniu, rzecz jasna) dla aplikacji pracujących pod kontrolą różnych wariantów Uniksa. W tym celu określone jest pokaźnych rozmiarów API, które zajmować ma się takimi rzeczami jak procesy, wątki, sygnały, I/O, gniazda sieciowe, i tak dalej.
To, co POSIX w tym zakresie teoretycznie oferuje, jest w gruncie rzeczy całkiem zadowalające. Standard nie zabrania zresztą, by implementujące go systemy operacyjne dodawały do tego jakąś własną funkcjonalność.
Dlaczego więc zgodność poszczególnych systemów z POSIX-em jest w przybliżeniu odwrotnie proporcjonalna do ich popularności? :-) Wbrew pozorom te co bardziej znane, jak różnego rodzaju BSD i dystrybucje Linuksa, nie są pod tym względem doskonałe. Jedynie znacznie bardziej specyficzne Solarisy, QNX-y oraz, co ciekawe, Mac OS X spełniają standard POSIX-a w pełni.
A co z naszymi ulubionymi okienkami? W ich przypadku jesteśmy oczywiście bardzo, bardzo daleko… ale tylko do czasu. Windows można bowiem dość prosto doprowadzić do pełnej zgodności przy pomocy takich pakietów jak Microsoft Windows Services for UNIX czy Cygwin. Może to być dobra pomoc dla tych, którzy chcą pisać przenośne aplikacje bez opuszczania przyjaznego środowiska okienek.
Zwolennicy C++ często argumentują, że w języku tym można bardzo, bardzo wiele. Kluczowe jest tu właśnie słówko ‘można’. Powiedziałbym mianowicie, że swego rodzaju potencjalność jest jego istotną cechą…
O co dokładnie chodzi? Najlepiej chyba mówią o tym przykłady – takie jak te poniższe:
finally
w blokach try
. W większości przypadków można jednak obejść się bez niej, stosując technikę znaną jako RAII (Resource Acquistion Is Initializon– pozyskanie zasobu inicjalizuje zmienną).Można więc to i tamto; powyższa lista z pewnością nie jest kompletna. Dawniej takie możliwości doskonale świadczyły o C++ jako o języku niebywale elastycznym. Robiły też dobrze dla jego efektywności oraz wstecznej kompatybilności z C. Krótko mówiąc, były niewątpliwymi zaletami.
Teraz jednak wydają się być listą braków, a w najlepszym przypadku niepodjętych, a koniecznych decyzji projektowych. Niezbędnych głównie dlatego, że twórcy nowszych języków nie wahali się ich podjąć. Dzięki temu w wielu przypadkach oszczędzili pracy i trudnych wyborów programistom, którzy z tych języków korzystają.
A programistom C++ wciąż pozostają możliwości… Niestety, aplikacji nie buduje się z kodu, który można by napisać, lecz z kodu już napisanego. Dlatego korzystanie z owych możliwości zamienia się często w uzupełnianie braków. I realizujemy wtedy stare powiedzenie: Jeśli programista chce mieć coś napisane, powinien napisać to sobie sam :P