{{page>courses:b6b36pjc:styles#common&noheader&nofooter}} {{page>courses:b6b36pjc:styles#ukoly&noheader&nofooter}} ===== Jednohubky ===== ==== 00 – Formátovaný zápis do proudu ==== V této jednohubce budete mít za úkol naimplementovat jednoduchou funkci, ''write_stats'', která bere dva argumenty, sadu dat a výstupní proud, a do výstupního proudu zapíše 3 statistické údaje o datech: minimum, maximum a průměr. Údaje musí být zapsány ve specifickém formátu, například pro vstupní data "1.23, 5.44, -23" by výstup vypadal takto: min: -23.00 max: 5.44 mean: -5.44 //Všimněte si, že čísla jsou vždy vypsaná se dvěma desetinnými čísly.// Projekt s testy najdete {{:courses:b6b36pjc:ukoly:tiny-00.zip|zde}}. Do Brute odevzdávejte pouze Váš soubor ''tiny-00.cpp'' s vaší implementací funkce ''write_stats''. === Rady === Formátovací manipulátory, které budete potřebovat, najdete v jedné ze dvou hlaviček: * [[http://en.cppreference.com/w/cpp/header/iomanip|iomanip]] * [[http://en.cppreference.com/w/cpp/header/ios|ios]] Zároveň vás může zajímat šablona [[https://en.cppreference.com/w/cpp/types/numeric_limits|numeric_limits]], přes kterou můžete získat informace o největší možné hodnotě typu a další podobné informace. ==== 01 – Kopie a reference ==== V této jednohubce dostanete rozpracovaný kód implementující dvě přetížení funkce ''pluralize'', specificky * ''std::string pluralize(std::string const& str);'' * ''std::vector pluralize(std::vector const& str);'' Jak název napovídá, úkol této funkce je převést předané slovo, případně vektor slov, na jejich množné číslo. V kódu který máte je ovšem chyba, takže část testů neprochází, a vaším úkolem je změnit kód který dostanete tak, aby všechny testy procházely. Projekt s testy najdete {{:courses:b6b36pjc:ukoly:tiny-01.zip|zde}}. Do Brute odevzdávejte pouze zazipovaný soubor ''tiny-01.cpp'' s vašimi změnami. === Rady === Tento úkol si můžete udělat velmi těžký, nebo velmi jednoduchý. Proto vám doporučujeme si před hledáním chyby v kódu pustit testy a rozmyslet si, co vidíte na výstupu. ==== 02 – Práce s dynamicky alokovanou pamětí ==== V této jednohubce znovu dostanete již hotový kód, ale narozdíl od minulé jednohubky všechny testy procházejí. To ovšem neznamená, že je s ním vše v pořádku -- jak název napovídá, obsahuje chybu práce s dynamicky alokovanou pamětí. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-02.zip|zde}}. //Poznámka k implementaci: funkcionalita funkce ''summarize_data'' je popsána uvnitř hlavičky ''tiny-02.hpp'' anglicky. Pro jistotu ji zde uvádíme i česky. Funkce ''summarize_data'' vrací statistiky pro každý validní řádek uvnitř předaného proudu. Nevalidní řádky jsou přeskočeny. Samotný řádek začíná číslem **n**, které určuje kolik čísel na řádku následuje. Následná čísla musí být z rosahu [0, 255].// === Rady === Pokud jste na Linuxu, již mnohokrát zmiňovaný [[http://valgrind.org/|Valgrind]] vám řekne k jaké chybě dochází a kde. Pokud jste na Windows, doporučujeme [[http://drmemory.org/|Dr. Memory]], který funguje zhruba stejně jako Valgrind. Pokud používáte aktuální verzi OS X, Valgrind vám bohužel nebude fungovat, budete tedy muset použít o něco komplikovanější nástroj jménem [[https://clang.llvm.org/docs/AddressSanitizer.html|AddressSanitizer]]. ==== 03 – Život objektů ==== Poučen problémy v minulé jednohubce se programátor rozhodl opravit kód ''summarize_data'' tak, aby ke stejné chybě již nemohlo dojít. Vytvořil si tedy třídu ''fixed_array'', která za alokované pole zodpovídá a vždy ho správně uvolní. Bohužel se to zcela nepovedlo a na vás je, abyste to opravili. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-03.zip|zde}}. //Též trochu změnil formát výstupu, protože si uvědomil, že když se špatné řádky prostě vypustí, tak není možné zpětně zjistit, které řádky nebyly platné. Nyní se tedy pro neplatné řádky vrací statistika, která říká, že na řádku bylo ''std::numeric_limits::max()'' prvků.// === Rady === Pokud se vám kompilátor snaží poradit, je dobrý nápad mu naslouchat. ==== 04 – Kopie a přesuny ==== V této jednohubce bude vaším úkolem doplnit funkční kopírovací a přesunující operace pro jednoduchý binární vyhledávací strom. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-04.zip|zde}}. === Rady === Připomeňte si obsah odpovídající cvičení. ==== 05 – Operátory ==== V této jednohubce si vyzkoušíte přetěžování operátorů pro třídu. Specificky se jedná o třídu ''pjc::complex'' a matematické operátory ''+'', ''-'' a ''*'' (pouze v binární variantě). Specificky chceme, aby šly sčítat (respektive odčítat nebo násobit) dvě instance třídy ''pjc::complex'' nebo instance třídy ''pjc::complex'' s ''double''. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-05.zip|zde}}. Do Brute tentokrát odevzdejte i vámi změněnou hlavičku ''tiny-05.hpp''. === Rady === Pokud si nepamatujete jak fungují dané operace nad komplexními čísly, [[https://cs.wikipedia.org/wiki/Komplexn%C3%AD_%C4%8D%C3%ADslo#Operace_s_komplexn%C3%ADmi_%C4%8D%C3%ADsly|wikipedie poradí]]. ==== 06 – Nevirtuální a virtuální rozhraní ==== V této jednohubce vás čeká modifikace již existující virtuální hierarchie tříd. Specificky se jedná o hierarchii různých generátorů náhodných čísel a vaším úkolem bude do ní doplnit sběr různých statistik: * Nejmenší/největší vygenerovaný ''int'', respektive ''double'' * Počet vygenerovaných ''int'', ''double'' čísel * Počet vygenerovaných ''bool'', včetně toho, kolik jich bylo pravdivých a kolik nepravdivých Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-06.zip|zde}}. Do Brute tentokrát odevzdejte i vámi změněnou hlavičku ''tiny-06.hpp''. === Rady === Existují dva způsoby, jak tuto jednohubku vyřešit. Jeden je pracnější, zabere vám delší dobu, ale nemusíte u něj vůbec přemýšlet. Alternativně můžete použít idiom, kterému se říká Nevirtuální rozhraní (NVI -- NonVirtual Interface), který umožňuje předkovi (rozhraní) vynutit, aby byly dodrženy invarianty během volání poděděných metod. NVI je implementace návrhového vzoru "Template Method" (šablona, šablonová metoda), specifická pro C%%++%%. Bohužel se nám nepovedlo najít dobrý text vysvětlující specificky NVI v češtině, ale [[https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface|WikiBooks]] obsahuje dobré vysvětlení v angličtině. ==== 07 – Simulace kovariantních návratových typů s chytrými ukazateli ==== Jak jsme si ukazovali na cvičení, v C%%++%% nelze kombinovat kovariantní návratové typy s chytrými ukazately, jako je například ''std::unique_ptr''. Nicméně, chytrou kombinací nevirtuálního rozhraní, schovávání, virtuálního rozhraní a boilerplate, se dá kovariance simulovat. V této jednohubce budete znovu pracovat s hierarchií tříd které generují náhodná čísla a vaším úkolem bude doplnit metodu ''clone'', která vrací příslušně konkretizovaný ''std::unique_ptr'' a zároveň se chová polymorfně. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-07.zip|zde}}. Do Brute odevzdejte i vámi změněnou hlavičku ''tiny-07.hpp''. === Rady === Je jasné, že metoda ''clone'' nemůže být virtuální, ale pro její správné chování potřebujete virtuální polymorfismus. Jinak řečeno, budete muset těch metod implementovat více. ==== 08 – Jednoduchá šablonová funkce ==== V této jednohubce si napíšete jednoduchou šablonovou funkci ''clamp''. Tato funkce se v C%%++%%17 stala součástí standardní knihovny, ale protože v tomto předmětu používáme tento semestr stále ještě C%%++%%14, budeme ji implementovat my. Funkce ''clamp'' má dvě přetížení * ''T const& clamp(T const& value, T const& low, T const& high)'' * ''T const& clamp(T const& value, T const& low, T const& high, Compare cmp)'' které vrací ''low'' pokud ''value'' je menší než ''low'', ''high'' pokud ''value'' je větší než ''high'' a jinak ''value''. Jinak řečeno, ''value'' je omezeno do rozsahu ''[low, high]''. První overload předpokládá, že ''T'' je porovnatelné pomocí operátoru ''<'', druhý overload pak bere vhodný komparátor jako 4. argument. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-08.zip|zde}}. Do Brute odevzdejte vaši hlavičku ''tiny-08.hpp''. === Rady === Není potřeba implementovat obě funkce stejně, můžete implementovat jednu voláním druhé. K tomu se vám bude hodit obsah hlavičky [[https://en.cppreference.com/w/cpp/header/functional|functional]]. === Další === K této jednohubce vám navíc nabízíme dvě otázky k zamyšlení: * Pokud uživatel předá parametry ve špatném pořadí, může dostat špatný výsledek. Toto se dá opravit, pokud funkci přejmenujeme((A změníme implementaci tak, aby odpovídala novému jménu)). Jaké jméno by to bylo? * ''const int& clamped = clamp(value, 0, 255);'' může vést k chybě. K jaké? Jde to rozumně opravit? ==== 09 – Jednoduché metaprogramování ==== V této jednohubce se naposled vrátíme k naší implementaci ''vector'' ze cvičení. Poslední, co jsme s ním dělali, byla optimalizace metody ''push_back(Iterator, Iterator)'' dle typu iterátoru, kterou dostala. V této jednohubce budeme podobně optimalizovat zvětšování (a kopírování) vektoru v závislosti na typu, pro který je náš ''vector'' instanciovaný. Specificky to znamená, že budeme rozlišovat 3 druhy typů, * Triviálně kopírovatelné typy * Typy, které mají přesunující přiřazení označené jako ''noexcept'' a nejsou triviálně kopírovatelné * Ostatní typy a budeme se k nim chtít chovat jinak, když budeme rozšiřovat pole uvnitř vektoru. Specificky, triviálně kopírovatelné typy chceme kopírovat pomocí [[https://en.cppreference.com/w/cpp/string/byte/memcpy|memcpy]], typy, které nejsou triviálně kopírovatelné, ale nemohou vyhodit výjimku při přesunujícím přiřazení, chceme opravdu přesunout a typy, které výjimku vyhodit mohou, chceme prostě zkopírovat. Projekt s implementací a testy najdete {{:courses:b6b36pjc:ukoly:tiny-09.zip|zde}}. Do Brute odevzdejte hlavičky ''array.hpp'', ''vector.hpp'' a případné jiné hlavičky které jste vytvořili. **K zjištění, jestli je typ triviálně kopírovatelný používejte ''pjc::is_trivially_constructible'' z ''pjc-traits.hpp'', a ne ''std::is_trivially_constructible''.** === Rady === Pro implementaci tohoto úkolu doporučujeme použít SFINAE (viz přednáška), a ne tag dispatch, který byl použit na cvičení. Jestli přesunující přiřazení daného typu je noexcept se dá zjistit pomocí traitu [[https://en.cppreference.com/w/cpp/types/is_move_assignable|is_nothrow_move_assignable]] ze standardní knihovny. === Další === Triviálně kopírovatelné typy jsou typy s triviálním kopírovacím konstruktorem a přiřazením. Méně kruhově definováno, jsou to typy u kterých je volání kopírovacích operací ekvivalentní se zkopírováním jejich bitové reprezentace((Toto striktně řečeno není pravda pro typ ''trivially_copyable_tracker'', proto jsme zavedli ''pjc::is_trivially_constructible'' trait a specializovali ho pro tento typ.)). Důvod, proč nechceme přesouvat typy, které mohou vyhodit výjimku je poskytnutí tzv. silné záruky. Detaily jsou v přednášce "Exception Safety", hrubý nástin pak je, že pokud dojde k chybě během zvětšování vektoru, tak se silnou zárukou zůstanou původní prvky zachovány a nepřijdeme o data.