Archive for Programming

Proste gesty dotykowe

2011-04-20 19:38

Urządzenia, w których jedyną lub główną metodą interakcji jest ekran dotykowy prezentują interesują wyzwanie w zakresie sterowania i interfejsu użytkownika. Naiwne w rozwiązania zwykle sprawdzają się słabo, czego przykładem może być wydzielenie części ekranu na przyciski kontrolne. Brak skoku oraz fizycznych krawędzi klawiszy sprawia, że stosunkowo łatwo tutaj o pomyłkę i niezamierzone wciśnięcie błędnego klawisza.
Dlatego też ta forma komunikacji użytkownika z urządzeniem wymaga nieco innego podejścia, które wykorzystuje jego mocne punkty i pozwala jakoś żyć z jego słabymi stronami. Można na przykład zauważyć, że palec użytkownika jeżdżący po ekranie (pozwolę sobie pominąć tutaj multitouch :)) przypomina pod wieloma względami kursor myszki i często można z powodzeniem traktować go jako taki. Podstawową różnicą jest brak wykrywalnego ruchu między miejscami interesującymi użytkownika, a co za tym idzie brak również zdarzeń typu hover (mouseover), służących często do wyświetlania podpowiedzi.


Jak się tapuje :) (Źródło)

Jest więc podobnie, ale inaczej :) Ponieważ nie mażemy palcem po ekranie przez cały czas, interakcja użytkownika z urządzeniem przebiega wyłącznie za pośrednictwem zamierzonych gestów. Częściowo przypominają one kliknięcia lub przeciąganie wykonywane jednoprzyciskową myszą, ale ich wachlarz jest nieco szerszy. Wśród nich mamy bowiem takie gesty jak:

  • Tap, czyli po polsku ‘tapnięcie’ ;-) Jest to krótkie naciśnięcie (albo wręcz puknięcie) ekranu. To najkrótszy i prawdopodobnie najprostszy gest (chociaż słyszałem też opinie wprost przeciwne), który służy standardowo do wyboru wskazanego elementu. W ten sposób uruchamia się aplikacje lub przechodzi do stron wskazywanych przez linki. Gest ten jest więc funkcjonalnym odpowiednikiem pojedynczego lub podwójnego kliknięcia w przypadku zwykłej myszki.
  • Long press, czyli dłuższe wciśnięcie. Polega ono na naciśnięciu ekranu i przytrzymaniu palca w jednym miejscu, zwykle około sekundę. Taki gest często daje dostęp do drugorzędnej akcji związanej z wciskanym elementem, a czasami po prostu otwiera menu zawierające większą liczbę opcji. Przybliżonym odpowiednikiem long pressa w przypadku myszki jest więc kliknięcie prawym przyciskiem.
  • Double tap, czyli podwójne tapnięcie. Oznacza to wykonanie dwóch tapów w krótkim odstępie czasu i przestrzeni (na ekranie). Chociaż wydaje się to podobne do dwukrotnego kliknięcia, analogia jest raczej błędna. Podwójny tap wykorzystywany więc bowiem stosunkowo rzadko i raczej tylko w dość specjalnych przypadkach. Jednym z powodów jest fakt, że obsługa tego gestu opóźniałaby każdy zwykły (pojedynczy) tap, gdyż użytkownik potrzebowałby okienka czasowego na “zdecydowanie się” na ewentualne drugie tapnięcie.
    Dlatego też często stosowaną strategią jest obsługa double tapu tylko w obrębie przestrzeni między interaktywnymi elementami. Wtedy gest ten służy do przełączania między widokiem zwykłym a przybliżonym/powiększonym – czyli po prostu do zoomowania.
  • Swipe lub fling, czyli przeciąganie. Podobnie jak w long pressie tu też wciskamy ekran na dłużej, ale tym razem przeciągamy palec w inne miejsce bez jego odrywania. Ten gest w rzeczywistości tysiąc razy prostszy niż nawet ten jednozdaniowy opis i niezwykle intuicyjny, więc używa się go w bardzo wielu miejscach. Obejmuje to: przechodzenie do następnego/poprzedniego elementu, przewijanie długich list, przeciąganie elementów w stylu drag & drop i pewnie jeszcze sporo innych zastosowań. Łatwo więc zauważyć, że odpowiednikiem dla zwykłej myszki może tu być zarówno standardowe przeciąganie z wciśniętym przyciskiem, jak i kręcenie rolką.

Jak widać, istnieją pewnie nieformalne standardy obsługi poszczególnych gestów w taki sposób, aby interfejs użytkownika był w miarę spójny. Zdaje mi się jednak, że ekrany dotykowe – mimo postulowanej intuicyjności – wciąż mogą niedoświadczonym użytkownikom wydawać się nieco zagadkowe w obsłudze. Spójna obsługa powyższych gestów w aplikacjach pomogłaby oczywiście w eliminacji tego problemu.

Tags: , ,
Author: Xion, posted under Applications, Programming » 2 comments

Do czego przydaje się AJAX

2011-04-16 22:44

Kiedyś wymyślono, że statyczne strony WWW są nieco nudne i że trochę bardziej zaawansowanej logiki mogłoby dodać im funkcjonalności. Powstał więc język JavaScript, który po pewnym czasie (gdy minął okres wykorzystywania go do animowanych zegarków, spadających płatków śniegu i innych niepoważnych zastosowań) znacząco zyskał na funkcjonalności. Dorobił się między innymi możliwości wysyłania dodatkowych żądań HTTP, niezależnie od pierwotnego requestu, wczytującego całą stronę.
Technika ta jest znana jako AJAX, czyli Asynchronous Javascript And XML. Ten łatwo wpadający w oko akronim jest notabene jednym z najbardziej nietrafnych, jakie da się znaleźć w całej szerokiej domenie informatyki. Jest tak dlatego, gdyż żądania HTTP wysyłane ze skryptów strony WWW:

  • wcale nie muszą być asynchroniczne, chociaż zwykle są
  • wcale nie muszą być kodowane w języku JavaScript (chociaż niemal zawsze są)
  • wcale nie muszą zwracać wyniku w formacie XML, bo zwykle używa się prostszych formatów

Ważna jest tu zwłaszcza uwaga ostatnia. Chociaż API do wysyłania żądań HTTP składa się z klasy o nazwie XMLHTTPRequest, to w istocie nie ma obowiązku korzystania z wbudowanego w nią parsera XML. Równie dobrze potrafi ona zwrócić odpowiedź serwera HTTP w postaci tekstowej, którą możemy potem przetworzyć ręcznie. W praktyce chyba najbardziej popularnym formatem zwrotnym dla zapytań AJAX-owych jest opisywany już przeze mnie JSON.
Oczywiście, nikt przy zdrowych zmysłach nie pisze samodzielnie kodu do owego “przetwarzania ręcznego” odpowiedzi z serwera. Zarówno ten końcowy etap, jak i samo wysyłanie żądania zostało bowiem opakowane w kilka użytecznych frameworków. Jednym z nich jest choćby jQuery, który poza ukrywaniem zbędnych szczegółów AJAX-u posiada też mnóstwo innych przydatnych funkcji ogólnego przeznaczenia.

Do czego może przydać się możliwość łączenia się z serwerem HTTP z poziomu Javascript? Żeby znaleźć odpowiedź, wystarczy dobrze przyjrzeć się właściwie dowolnej bardziej skomplikowanej stronie internetowej..Prawie na pewno znajdziemy na niej mechanizmy, które w tle pobierają dodatkowe dane z macierzystego serwera lub wysyłają doń jakieś informacje. Dzięki temu mogą one realizować takie funkcje jak:

  • Dynamicznie pobieranie nowych treści, które pojawiły się od czasu przeładowania witryny. Ładnym przykładem takie zachowania jest Twitter. Jeśli zostawimy stronę otwartą w zakładce przeglądarki, wówczas po jakimś czasie możemy odnaleźć na niej ramkę z napisem w rodzaju “2 new tweet(s)”, po kliknięciu której zobaczymy od razu nowe statusy.
  • Doczytywanie starszych elementów w trakcie przewijania. To odwrotny (chronologicznie) przypadek do powyższego, będący alternatywą dla stronicowania. Przykładem strony świetnie stosującej to rozwiązanie jest dzone.
  • Wyświetlanie szczegółów elementu, na przykład w dymku (tooltip) po najechaniu na niego kursorem myszy lub po rozwinięciu do większej postaci. Oczywiście ma to sens głównie wtedy, gdy treść do pobrania jest na tyle duża, że nie jest rozsądne dostarczanie jej wraz z pierwotną treścią strony.
  • Wysyłanie formularzy bez przeładowywania strony. Normalnie przesłanie formularza na stronie skutkuje jej przeładowaniem w wyniku żądania typu POST (rzadziej GET). Można jednak przechwycić zdarzenie wysłania formularza i zamiast niego przesłać zapytanie AJAX-owe. Sensownym wykorzystaniem tej techniki jest weryfikacja nazwy użytkownika po wciśnięciu osobnego przycisku w formularzy rejestracyjnym do wielu serwisów sieciowych.
  • Podpowiadanie zapytań w przypadku wyszukiwania. Tutaj nietrudno o przykłady, bo robią to wszystkie wyszukiwarki internetowe ogólnego przeznaczenia, a także sporo dedykowanych mechanizmów wyszukiwania obecnych w serwisach sieciowych.
  • Synchronizacja edytowanego dokumentu (Google Docs), obsługa czata (Facebook), map (Google Maps) i wielu innych zaawansowanych logicznie aplikacji webowych.
Tags: , , ,
Author: Xion, posted under Internet, Programming » 6 comments

Przenośne aplikacje mobilne

2011-04-05 21:07

Odkryłem niedawno bardzo ciekawy projekt o nazwie jQuery Mobile. Jego założeniem jest uproszczenie procesu tworzenia aplikacji na różne platformy mobilne poprzez dostarczenie odpowiednio przenośnego frameworka webowego. Powstałe przy jego pomocy “aplikacje” (a tak naprawdę odpowiednio spreparowane strony) mają wyglądać i działać tak samo na większości przenośnych urządzeń takich jak smartphone‘y i tablety.

Całkiem interesujące, prawda? Jeszcze ciekawsze jest to, że mimo bycia wciąż w stadium alpha (wersję alpha 4 wydano parę dni temu) całość działa już bardzo dobrze i rzeczywiście spełnia większość swoich obietnic. Oczywiście nie każdemu może uśmiechać się “programowanie w HTML” (;D), ale tutaj jest ono dość ładnie zorganizowane w warstwę interfejsu (odpowiednio spreparowane tagi HTML) i logiki (kod JavaScript wykorzystujący jQuery). Ta pierwsza pozwala między innymi na umieszczanie kilku stron w jednym pliku i efektowne przełączanie miedzy nimi:

  1. <div data-role="page" id="menu">
  2.     <div data-role="content">
  3.         <ul data-role="listview">
  4.             <li><a href="#one">One</a></li>
  5.             <li><a href="#two">Two</a></li>
  6.         </ul>
  7.     </div>
  8. </div>
  9. <div data-role="page" id="one">
  10. ...
  11. </div>
  12. <div data-role="page" id="two">
  13. ...
  14. </div>

Przejścia pomiędzy stronami nieźle imitują natywny UI platform mobilnych, gdyż są zrealizowane przy pomocy javascriptowych animacji zaimplementowanych w jQuery. Co więcej, jak widać powyżej odnośniki mogą być zwykłymi linkami (<a>). Czego zaś nie widać to to, że przy okazji przechodzenia między stronami historia przeglądarki – a więc chociażby przyciski Wstecz i Dalej – działa zgodnie z przewidywaniami i “nie psuje” zachowania aplikacji.
Naturalnie samo przełączanie stron to nie wszystko, bo wypadałoby przecież coś na nich pokazać :) Tutaj jQuery Mobile też prezentuje się dobrze, bo niejako automagicznie dba o odpowiedni wygląd elementów aplikacji poprzez stosowanie wbudowanego zestawu “mobilnych” stylów CSS. Zmieniają one wygląd tekstu, linków oraz pól formularzy na taki, który dobrze udaje kontrolki natywnego interfejsu. No, a przynajmniej może uchodzić za takowy w przypadku urządzeń pracujących pod kontrolą iOS-a, bo właśnie do interfejsu tego systemu aplikacje jQuery Mobile są najbardziej podobne.

Niemniej także na innych platformach (chociażby Androidzie) rezultat zastosowania tego frameworka jest więcej niż zadowalający. Wydaje mi się aczkolwiek, że podobne rozwiązania chwilowo wyprzedzają jeszcze trochę swój czas. Ich podstawowym mankamentem jest brak sensownych dojść z przeglądarki internetowej do większości ciekawych podsystemów urządzeń mobilnych, takich chociażby jak kamera; póki co dostępne są chyba tylko usługi lokalizacyjne. Nie da się więc w ten sposób tworzyć skomplikowanych aplikacji, korzystających ze sprzętu czy bardziej zaawansowanych funkcjonalności systemu.
Jeśli jednak chodzi o proste rozwiązania oparte na tekście, obrazkach i formularzach – a więc jako szeroko pojęte front-endy do zdalnych repozytoriów z danymi – to jQuery Mobile może być dobrą alternatywą dla mozolnego portowania aplikacji między różnymi platformami. Podobnie zresztą rzecz ma się z mobilnymi wersjami zwykłych stron internetowych.

Tags: , , ,
Author: Xion, posted under Applications, Internet, Programming » 8 comments

Powtórka z rozrywki

2011-03-28 19:38

Kolejna konferencja IGK zakończyła się wczoraj tradycyjnym konkursem zespołowego programowania gier Compo. Podobnie jak w zeszłym roku startowało wiele zespołów, w tym także i mój, czyli Rzeźnicy Inc. ;) I podobnie jak zawsze, wszyscy starali się zakodować jak najlepiej wyglądające, najbardziej grywalne, najoryginalniejsze i w ogóle najlepsze gry. Naturalnie nie wszystkim się to udało, ale akurat w przypadku mojej drużyny rezultat był chyba całkiem niezły. W każdym razie zasłużył na drugie miejsce, czyli analogicznie jak w zeszłym roku. Krótko mówiąc: trzymamy poziom :)

W najbliższych dniach postaram się zamieścić na stronie jakąś grywalną wersję naszej pracy.

Tags: ,
Author: Xion, posted under Events, Games, Programming » 3 comments

Moda na krytykowanie OOP-u

2011-03-19 20:47

Nauczyłem się już lubić fakt, że w przypadku informatyki powiedzenie o “ciekawych czasach” jest truizmem, bo ciekawie jest po prostu zawsze – głównie ze względu na tempo zmian w wielu dziedzinach. Nawet w tych, wydawałoby się, zastygłych na lata. Niecałe trzy lata temu zżymałem się na przykład na zbytnią ufność w doskonałość obiektowych metod programowania. Dzisiaj zaś przychodzi mi robić coś zdecydowanie przeciwnego.
Programowanie obiektowe jest obecnie sztandarowym kozłem ofiarnym i chłopcem do bicia, otrzymującym ciosy z wielu stron. Już nie tylko programiści gier twierdzą, że nie mogą sobie na nie pozwolić ze względu na wydajność i zamiast niego forsują Data Oriented Design. Pokazywałem niedawno, że sprzeczność między tymi dwoma podejściami jest raczej pozorna niż rzeczywista. Teraz natknąłem się na interesującą opinię, która podważa sens OOP-u jako metodologii, wychodząc z nieco innego punktu widzenia niż wydajność dla celów grafiki real-time:

Object-oriented programming (…) is both anti-modular and anti-parallel by its very nature, and hence unsuitable for a modern CS curriculum. [pogrubienie moje]

Anty-modularne i anty-współbieżne? Oczywiście; da się napisać kod obiektowy, który te dwa warunki będzie spełniał doskonale. Ale to nie oznacza, że każdy kod obiektowy je spełnia, a to właśnie jest implikowane powyżej. Nie da się tego określić inaczej niż jako stereotyp – i to w modelowej wersji, czyli negatywnego uogólnienia z pojedynczych przypadków.

Jako antidotum na te rzekome bolączki OOP-u często wymieniane jest programowanie funkcyjne. Nie ujmując mu niczego ze swojej elegancji, nie mogę jednak nie zauważyć, że zamiata ono wiele problemów pod dywan. Określanie wykonania programu jako serii transformacji danych nie rozwiązuje jednak problemu: gdzie i jak te dane mają być zapisywane i chronione przed równoczesnym dostępem z wielu ścieżek wykonania. Sytuacje, w których programowanie funkcyjne lub quasi-funkcyjne sprawdza się dobrze to takie, gdzie problemy te dały się w miarę łatwo rozwiązać. Tak jest chociażby w przypadku vertex i pixel shaderów, gdzie podział danych wejściowych i wyjściowych na rozłączne bloki jest wręcz naturalny. Fakt ten nie jest jednak zasługą programowania funkcyjnego, tylko natury zagadnienia – w tym przypadku renderowania grafiki opartej na wielokątach.

I właśnie o tym powinniśmy pamiętać, gdy wyzłośliwiamy się nie tylko na OOP, ale dowolny inny paradygmat programowania. Otóż porzucenie go nie sprawi od razu, że magicznie zaczniemy pisać kod doskonale modularny. A już nie pewno nie spowoduje, że niezwykle trudne zagadnienia współbieżności staną się nagle banalnie proste. To niestety tak nie działa.
Nie znaczy to oczywiście, że nie powinniśmy poszukiwać nowych, lepszych metodologii do konkretnych zastosowań. Dlatego przecież wiele języków (np. C++, C#, Python) ewoluuje w kierunku wieloparadygmatowości, aby możliwe było dobranie właściwych narzędzi dla danej sytuacji. Nie wydaje mi się jednak, aby uleganie trendy nurtom krytykowania jakichkolwiek rozwiązań poprzez odwoływanie się do stereotypów i nieuzasadnionych wyobrażeń o nich było w tym procesie specjalnie produktywne. Zdaję sobie jednak sprawę, że “funkcje wirtualne to zuo!” brzmi lepiej niż “wywoływanie funkcji wirtualnych skutkuje narzutem wydajnościowym związanym z dodatkowym adresowaniem pamięci (które nie jest cache-friendly) i może powodować niepożądane skutki uboczne, jeśli ich wersje w klasach pochodnych nie są thread-safe“. Mam jednak nadzieję, iż nikt nie ma wątpliwości, które z tych dwóch stwierdzeń jest bardziej racjonalne.

Podziękowania dla Rega za podesłanie linków, które zainspirowały mnie do podjęcia tego tematu.

Importy niezupełnie z zagranicy

2011-03-17 23:55

Przeglądając plik źródłowy programu w dowolnym niemal języku, gdzieś bardzo blisko początku znajdziemy zawsze region z importami. Niekoniecznie będą one oznaczone słowem kluczowym import – czasem to będzie using, być może do spółki z #include – ale zawsze będą robiły zasadniczo to samo. Chodzi o poinformowanie kompilatora lub interpretera, że w tym pliku z kodem używamy takich-a-takich funkcji/klas/itp. z takich-a-takich modułów/pakietów. Dzięki temu “obce” nazwy użyte w dalszej części będą mogły być połączone z symbolami zdefiniowanymi gdzie indziej.

Każdy import w jakiś sposób rozszerza więc przestrzeń nazw danego modułu i zazwyczaj wszystko jest w porządku, dopóki dokładnie wiemy, jak to robi. Dlatego też powszechnie niezalecane są “dzikie” importy (wild imports), które nie wyliczają jawnie wszystkich dodawanych nazw, zwykle ukrywając je za gwiazdką (*). Ale nawet jeśli ich nie używamy, to nie oznacza to, że żadne problemy z importowanymi nazwami nas nie spotkają. Oto kilka innych potencjalnych źródeł kłopotów:

  • Importowanie nazwy, która jest identyczna z jednym z symboli zdefiniowanych w tym samym pakiecie. Import będzie wtedy ją przesłaniał – ale oczywiście tylko wtedy, jeśli go rzeczywiście dodamy. A to nie jest takie pewne zwłaszcza w języku interpretowanym, gdzie nawet symbol o zupełnie innej semantyce może łatwo przejść niezauważony aż do momentu uruchomienia kodu z jego błędnym wystąpieniem. Możemy więc nieświadomie używać nazwy lokalnej tam, gdzie należałoby raczej zaimportować zewnętrzną – lub odwrotnie.
  • Zaimportowane nazwy mogą być kwalifikowane lub nie, zależnie od języka i/lub sposobu importowania. I tak chociażby fraza import foo.bar.baz; wprowadza do przestrzeni modułu nazwę baz (czyli niekwalifikowaną) w przypadku Javy. W przypadku Pythona ten sam efekt wymaga z kolei instrukcji from foo.bar import baz, a zwykła instrukcja import da nam jedynie kwalifikowaną nazwę foo.bar.baz – która z kolei w Javie i C# jest dostępna bez żadnych importów, a w C++ po dodaniu dyrektywy #include… Całkiem intuicyjne, czyż nie? ;-) Skoro tak, to dodajmy do tego jeszcze fakt, iż…
  • Nazwy importowane można w większości języków aliasować. Oznacza to, że wynikowa nazwa wprowadzona do przestrzeni może być zupełnie inna niż ta, która jest zdefiniowana w źródłowym module. Aliasowania używa się najczęściej do skracania prefiksów nazw kwalifikowanych i choć ułatwiają one ich wpisywanie, to w rezultacie ogólna czytelność kodu może się pogorszyć.
  • W wielu językach importy mają zasięg. Przekłada się on potem na zasięg zaimportowanych nazw, którego ograniczenie jest często dobrym pomysłem. Sam import występujący poza początkiem pliku może jednak mieć niepożądane efekty – jak choćby załadowanie do pamięci importowanego modułu dopiero w momencie jego pierwszego użycia, co może wiązać się z potencjalnie dużym, chwilowym spadkiem wydajności.
  • Jeśli nie jesteśmy uważni, możemy rozpropagować zaimportowane nazwy do kolejnych modułów, które bynajmniej wcale z nich nie korzystają. Chyba najbardziej znanym przykładem jest wstawianie deklaracji using w plikach nagłówkowych C++, ale to nie jedyny przypadek i nie jedyny język, w którym importy z jednego modułu mogą zaśmiecić przestrzeń nazw innego.

Podsumowując, importy – chociaż często zarządzane prawie całkowicie przez IDE – to w sumie dość poważna sprawa i warto zwrócić na nie uwagę przynajmniej od czasu do czasu.

Tags: , , , , , , ,
Author: Xion, posted under Programming » Comments Off on Importy niezupełnie z zagranicy

Najboleśniejszy strzał w stopę

2011-03-13 20:14

Znanych jest mnóstwo kruczków w języku C++, o których trzeba pamiętać, jeśli chcemy efektywnie w nim programować i nie tracić zbyt dużo czasu na odczytywanie niespecjalnie zrozumiałych komunikatów kompilatora czy – gorzej – drapanie się po głowie podczas debugowania naszego programu. O wielu z nich miałem okazję pisać, ale oczywiście ten temat-rzeka daleki jest od wyczerpania :) W jego nurcie wyróżnia się jednak jeden wybitnie złośliwy przypadek, który przez długi czas uważałem aczkolwiek za ciekawostkę, na którą w praktyce raczej nikt się nie natknie…
Rzecz jasna, myliłem się. Okazuje się, że okaz ten jak najbardziej występuje w rzeczywistym świecie. Nie objawia się wprawdzie zbyt często, ale dzięki temu jest jeszcze bardziej podstępny, posiadając tym większą siłę rażenia, gdy w końcu na kogoś trafi. Dobrze więc wiedzieć, co robić, aby się przed nim bronić :] I tym właśnie chciałbym się dzisiaj zająć.

Pewną pomocą jest tutaj fakt, iż opisywany błąd zdaje się zazwyczaj pojawiać w pewnym konkretnym scenariuszu. Jego wystąpienie w owym kontekście jest przy tym tak zaskakujące, że zetknięcie się z nim skutecznie “uodparnia” na wszelkie inne, podobne okoliczności w których problem może wystąpić. Rzeczony scenariusz jest przy tym bardzo typowy: chodzi o wczytanie zawartości pliku (otwartego jako strumień std::ifstream) do kolekcji albo zmiennej, na przykład łańcucha znaków typu std::string.
Są naturalnie tacy, co bawiliby się tutaj w bufor pomocniczy, pętlę i funkcję getline lub coś w tym guście. Programiści lubiący operować na nieco wyższym poziomie wiedzą jednak, że std::string możemy inicjalizować zakresem znaków określonym – jak każdy zakres w C++ – parą iteratorów. Trochę mniej znanym faktem jest z kolei to, że iterować można również po strumieniach. Mamy na przykład coś takiego jak std::istream_iterator, który potrafi automatycznie dekodować ze strumienia egzemplarze ustalonego typu danych:

  1. // odczytanie 10 liczb int z stdio
  2. vector<int> numbers(10);
  3. copy (istream_iterator< int >(cin),
  4.       istream_iterator< int >(), numbers);

Jeśli nam to nie odpowiada i wolimy dostęp do “surowych” bajtów, wtedy z pomocą przychodzi bardziej wewnętrzny std::istreambuf_iterator. To właśnie przy jego pomocy możemy szybko przejść po zawartości strumienia plikowego i umieścić ją w stringu:

  1. ifstream file("plik.txt");
  2. string fileContents(istreambuf_iterator< char >(file),
  3.                     istreambuf_iterator< char >());

Jak pewnie można się domyślić, zakres zdefiniowany przez te iteratory w obu przypadkach zaczyna się na początku strumienia. Kończy się zaś w miejscu, gdzie odczyt następnej porcji danych nie jest już możliwy. W naszym “rozwiązaniu” problemu wczytywania całego pliku będzie to więc koniec tego pliku, czyli to co nam chodzi.

Nieprzypadkowo jednak słowo ‘rozwiązanie’ ująłem w cudzysłów. Powyższe dwie instrukcje zawierają bowiem ów wyjątkowo perfidny błąd, o którym wspominałem na początku. Dość powiedzieć, że jeśli spowoduje on wygenerowanie przez kompilator bardzo tajemniczego komunikatu, będzie to lepszy z jego dwóch możliwych rezultatów. Drugim jest kompilacja zakończona powodzeniem i… kod, który robi dokładnie nic. Nie tylko nic nie wczytuje, ale nawet nie tworzy zmiennej typu string! To raczej zaskakujące, nieprawdaż? ;)

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


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