Co nowego w C++11? Część 1

Nie tak dawno we wrześniu został oficjalnie wydany nowy standard języka C++: C++11. Po 8 latach od poprzedniej edycji tego języka wprowadzono dosyć dużo nowinek zarówno w standardowej bibliotece STL jak i w samej składni języka. Postaram się pokrótce przedstawić (mam nadzieje, iż w kilku częściach) nowinki, które najbardziej mnie przypadły do gustu i które są wspierane przez co najmniej jeden z dwóch kompilatorów: GCC i/lub MS VC++. Napisałem “co najmniej”, gdyż na chwilę obecna niestety nie wszystkie kompilatory wspierają bądź co bądź jeszcze świeży standard. Aczkolwiek wiele rzeczy już jest zaimplementowane.

Przechodząc już do konkretów.. Pierwszym elementem, który chciałbym opisać jest nowe słowo kluczowe auto. Może nie jest ono do końca nowe, gdyż istniało już w poprzednich wersjach standardu, jednakże kompletnie zmieniło ono znaczenie. Zadaniem słowa kluczowego auto jest ułatwienie i skrócenie czasu pisania programów. Chodzi tutaj o automatyczne (ale co najważniejsze statyczne) wnioskowanie typu zmiennej na podstawie wyrażenia r-value na etapie kompilacji kodu.

Na przykład:

    auto i = 5;  		// zmienna typu int
    auto j = 2.5;		// zmienna typu float
    std::vector<double> v;
    auto it = v.begin(); 	// zmienna typu std::vector<double>::iterator

Jak widać w pierwszym i drugim przykładzie kodu co prawda niewiele zostało zaoszczędzone. Ale załóżmy, że w naszym projekcie powszechnie stosujemy iteratorów oraz za każdym razem chcemy deklarować nowe zmienne przechowujące odpowiedni iterator. W takim przypadku należy zazwyczaj podać pełna nazwę typu, np.: std::vector<double>::iterator. Pól biedy gdy mamy do czynienia z szablonami o jednym argumencie, gorzej natomiast, gdy chcemy iterować po nieuporządkowanej mapie której kluczem jest para dwóch liczb całkowitych a wartościami tablice liczb zmiennoprzecinkowych. No ok, może przypadek trochę wyolbrzymiony, ale porównajmy zapisy:

    std::unordered_map<std::pair<int, int>, std::vector<double> > collection;
    std::unordered_map<std::pair<int, int>, std::vector<double> >::iterator it_manual = collection.begin();
    auto it_auto = collection.begin();

oraz pętle:

    for (std::unordered_map<std::pair<int, int>, std::vector<double> >::iterator it_manual = collection.begin(); it != collection.end; ++it) {
        ....
    }
    for (auto it_auto = collection.begin(); it != collection.end; ++it) {
        ....
    }

Jak można łatwo zauważyć otrzymujemy zarówno duży zysk płynący zarówno z oszczędności pisania kodu jak i jego czytelności, no i najważniejsze, że nie potrzeba już pamiętać jakiego dokładnie typu była nasza kolekcja.

Obliczenia na typach generycznych w C#

Rozwijam właśnie aplikację w której niezbędne jest przeprowadzanie obliczeń na niekoniecznie z góry znanych typach. W celu zapewnienia elastyczności poszczególnych klas zdecydowałem się na implementacje klas generycznych. Załóżmy, że mamy taką oto klasę:

1
2
3
4
public class Klasa< T > {
    public T Field1;
    public T Field2;
}

Następnie utwórzmy metodę, która ma za zadanie zsumować oba pola i zwrócić wynik. Intuicyjnie powstanie taki kod:

1
2
3
    public T SumFields() {
        return Field1 + Field2;
    }

Jednakże podczas kompilacji zostaniemy uraczeni następującym błędem:
Error 1 Operator '+' cannot be applied to operands of type 'T' and 'T'

Po chwili zastanowienia nie można się kompilatorowi dziwić, nie każdy typ musi mieć zaimplementowany operator dodawania (a także odejmowania, mnożenia, itd.). Znająć z kolei chęci programistów Microsoft do projektowania interfejsów do „wszystkiego” zaczałem szukać takiego, który deklarowałby powyższe operatory. Niestety czegoś takiego jeszcze nie ma (może kiedyś będzie?). I należy się posiłkować innymi metodami.

W tym celu można wykorzystać wprowadzony w C# 4.0 nowy typ dynamic. Deklarując zmienną typu dynamic zmieniamy moment, w którym rozwiązywany jest jej typ. Normalnie proces ten jest realizowany w czasie kompilacji, natomiast w przypadku dynamic w czasie działania programu (podobnie jak w językach skryptowych bez ścisłego typowania).

Po drobnej modyfikacji metoda będzie wyglądała następująco:

1
2
3
4
    public T SumFields() {
        dynamic dField1 = Field1, dField2 = Field2;
        return dField1 + dField2;
    }

Windows SideShow i Windows Mobile

Windows SideShow jest usługą, która umożliwia szybki dostęp do niektórych funkcji systemu (zależnych tylko od wyobraźni programistów) z między innymi urządzeń posiadających mały ekran W sumie nie widziałem jeszcze działania tego podsystemu, aż do wczoraj…

W sumie zainteresowałem się tym już jakiś tydzień temu szukając jakichś fajnych gadżetów na mojego HTC Touch Diamonda (dorobiłem się w końcu jakiś czas temu, tak jak i nowego laptopa;) ). No i przypomniałem sobie o Windows Sideshow – usłudze, której nazwa co chwile wpadała w oczy podczas przeglądania panelu sterowania. Grzebiąc trochę w Internecie doszukałem się, że Microsoft wypuścił aplikacyjkę na Windows Mobile wykorzystującą właśnie Windows SideShow. Jaki jest efekt działania?

W tej chwili na komórce w momencie gdy jest połączona przez Bluetooth (po WiFi nie działa) mogę połączyć się z usługą Windows SideShow na laptopie i korzystać z zainstalowanych gadżetów. Gadżety można ściągnąć z MS Live Gallery, ale na chwilę obecną nie ma ich niestety zbyt wiele. W każdym bądź razie są dwa dosyć przydatne.

Office Powerpoint Remote oraz domyślnie zainstalowany gadget do Windows Media Playera. Ten drugi umożliwa zdalne sterowanie naszym WMP, a ten pierwszy czyni z naszego telefonu dosyć zaawansowany prezenter, który oprócz możliwości przełączania slajdów wyświetla również napisane notatki oraz wyświetla jaki będzie następny slajd. Co prawda ma jeszcze parę małych wad jak kiepskie przystosowanie do dotykowego ekranu, ale i tak cieżko znaleźć podobną aplikację i to za darmo :)

Linki:


Zarządzanie pamięcią pod Windowsem x64

Pracując przy projekcie, który bardzo mocno wykorzystuje obliczenia matematyczne, po raz pierwszy natknąłem się w praktyce na ograniczenia pamięciowe. W pierwszych wersjach systemu nie udało nam się tych ograniczeń zauważyć, gdyż operowaliśmy na małych próbkach danych rzędu 1000×20. Oczywiście należało sprawdzić działanie także dla większej próbki danych i wyskoczyło nam pierwsze z ograniczeń.

Początkowo prace deweloperskie przeprowadzane były na maszynie z systemem 32bitowym z pamięcią 4GB. Występuje tutaj zjawisko ograniczenia pamięci dla procesu do 2GB (ewentualnie do 3GB z odpowiednim przełącznikiem). Przez jakiś czas wystarczał nam obecny limit… Ale po co się ograniczać skoro procesory są 64bitowe? Tak więc po przeinstalowaniu systemu na Windows Server 2008 x64 nastąpiła przedwczesna radość z praktycznie zerowymi limitami (nie mam do dyspozycji serwera z 2TB pamięci RAM ;) ).

Pierwszym problem przy uruchamianiu aplikacji pojawił się z bibliotekami matematycznymi Intel Math Kernel Library, były jeszcze 32bitowe, ale nie sprawiło dużo kłopotów przerobienie jej na wersję 64bitową (aczkolwiek trzeba było trochę doczytać;P ).

W końcu z wielką radością w oczach aplikacja została odpalona i można było patrzeć jak rośnie słupek zajętości pamięci przez proces, urósł do około 4GB. No dobra, ale jakie tutaj są ograniczenia? Okazuje się, że najbliższym limitem jest ciągł obszar jaki można zaalokować. Próba zdefiniowania tablicy typu Byte o liczbie elementów większej niż 2^31 zakończyła się porażką (mniejszą bądź równą – należy wziąć jeszcze narzut platformy .NET – jak najbardziej udało się zaalokować). Dlaczego akurat tablica może mieć rozmiar tylko 2GB? No cóż, wina leży po stronie platformy .NET i środowiska CLR.

Następny krokiem była próba zaalokowania kilku tablic po 2GB każda. Niestety po 6 takich wyświetlił mi się wyjątek OutOfMemoryException (patrz rysunek)

Przyczyną braku pamięci zapewne była wielkość pliku wymiany, gdyż odpowiedni licznik pokazywał ładną liczbę 15999MB (rysunek). Zajętość co prawda wyniosła 14484MB, ale kolejne 2GB tutaj już się nie mieszczą ;)

Ostatecznie muszę stwierdzić, że o ile limit 2GB na wielkość ciągłej pamięci do zaalokowania może boleć (należałoby się zagłębić bardziej w jaki sposób można to obejść), to obszar pamięci dla jednego procesu jest jak na razie nie do zapełnienia dla mnie pożytecznymi danymi, a zawsze można jeszcze zwiększyć rozmiar pliku wymiany.

Warto przeczytać:

  1. BigArray<T>, getting around the 2GB array size limit
  2. Memory Limits for Windows Releases
  3. Zarządzanie pamięcią w 32 i 64-bitowych systemach Windows

Microsoft Word 2007 i blog

Jakiś czasem temu wspomniałem o tym, że notki na bloga można dodawać pisząc w Wordzie (w każdym bądź razie w MS Word 2007). Po jego uruchomienu wystarczy wybrać z menu nowy dokument i z listy szablonów „New blog post”. Niestety jest to proces bardzo denerwujący, gdyż odpala się druga instancja aplikacji z nowym szablonem, a stara (z klasycznym dokumentem) dalej zostaje uruchomiona w tle i trzeba to ręcznie zamykać…

Super sprawą byłoby zrobienie odpowiedniego skrótu, aby odrazu przenosił nas do odpowiedniego szablonu… Szperająć trochę w Internecie okazało się, że jest to naprawdę trywialny problem. Oto i jego rozwiązanie:

  1. Stworzyć nowy skrót
  2. Jako obiekt docelowy wybieramy winword.exe (domyślna ścieżka to: „C:\Program Files\Microsoft Office\OFFICE12\WINWORD.EXE” )
  3. Szukamy pliku naszego szablonu blog.dotx (domyślnie: „C:\Program Files\Microsoft Office\Templates\1033\Blog.dotx”)
  4. Łączymy oba ciągi znaków dodająć jeszcze parametr \t przed nazwą szablonu (ostatecznie będzie to coś w stylu :
    „C:\Program Files\Microsoft Office\OFFICE12\WINWORD.EXE” /t”C:\Program Files\Microsoft Office\Templates\1033\Blog.dotx” )
  5. Zapisujemy skrót, nadajemy odpowiednią nazwę i ewentualnie jakąś ikonkę :)
  6. Od teraz możemy się cieszyć większą wygodą podczas tworzenia nowych notek na blogu.