C++ - poznamky k zapoctovemu testu a zkouskam
- plny pristup k recodexu; moznost pouzivat cppreference.com (a cplusplus.com - ten je ale obecne vyrazne horsi nez cppreference, IMO)
- neni dovoleno pouzivat jine externi zdroje (vcetne AI)
- muzete pouzivat nastroje dostupne na skolnich pocitacich - urcite si je poradne vyzkousejte a zjistete si, jak je nakonfigurovat tak, aby se vam s nima pracovalo co nejlip (napr intellisense)
- mate dovoleno pouzivat jak windows, tak linux a libovolny editor; vse tohle, pokud se vam to behem testu/zkousky povede zprovoznit
- neni dovoleno ke skolnim pocitacum pripojovat vlastni hw (vcetne klavesnic, mysi, flash disku apod.)
- zaroven neni dovoleno pracovat na vlastnim hw
- pri otevirani noveho reseni (ve VS treba) pouzivejte lokalni disk, protoze je nejrychlejsi a nejspolehlivejsi - a hlavne se ujistete, ze je na nem dost mista (pokud ne, tak to nahlaste a zkuste jiny pocitac)
- tyhle veci by snad mely jit jeste pred zadanim ulohy
- pred zkouskou se ujistete, ze umite pracovat se cppreference - typicky u vetsiny clanku se prvni chcete podivat na examply a nebo na strucny popis nahore - vetsina clanku byva formatovana +- podobne, takze si na to zkuste pred zkouskou zvyknout
- (test) zadavatel by mel byt schopen problem vyresit do 15 minut (student pak maximalne x5 tolik casu)
- (test) je jeden opravny termin - sharovany, ale kazdy ma zadani podle sveho cviciciho
- reseni pak kontroluje cvicici daneho studenta
- cvicici nejspis bude dostupny online behem opravneho testu (pokud nebude zrovna na miste)
- (test) kazdy student ma pripravenou posledni ReCoDex ulohu (ktera je naprogramovatelna dostatecne rozsiritelne)
- zkousi se nejen programovani v C++ pri testu, ale i spravny design programu pri reseni ulohy - proto se hodi dat priprave vic energie, nez na jine recodexove ulohy
- (test) bude vice test-casu a budou (z vetsiny) verejne (jako u posledni ReCoDex ulohy)
- bude predem dano, kolik je potreba bodu pro zapocet; bohuzel, body jde ztratit pak pri rucni oprave, proto je opravdu lepsi, kdyz testy projdou na vice bodu, nez je limit
- (test) nelze prodlouzit cas - pokud mate nejake specialni pozadavky na cas nebo formu testu, hlaste je dostatecne brzo
- (test) vysledek je ANO/NE - vysledne body nemaji efekt na znamku
- je mozne pokladat otazky - ale odpovedi budou spise omezene na obecnejsi veci (samozrejme vcetne dovysvetleni ulohy) a budou receny vsem otevrene
- budou se strhavat body za jasne chyby (v listu ty asi nezavaznejsi)
- zbytecne kopirovani kontejneru a dalsich veci (pri predavani argumentu)
- (kontrolor by mel zjistit, jestli student alespon chape princip predavani referenci; pokud na to student zapomene jen na urcitych mistech, tak to bude stale chyba, ale mnohem mene zavazna - mela by byt relevantni jen, pokud bude v kodu vice podobnych chyb)
- vetsinou je chceme argumenty predavat const referencema
const object&
- mene casto normalnima referencema
object&
- nekdy rvalue referencema
object&&
- ty se pouzijou pri std::move(predavana_vec)- tim se “zbavujeme” toho predavaneho objektu (prijemce si s objektem muze delat, co chce)
- kazdy objekt bychom z jednoho mista meli movnout max. jednou (pri poslednim predani nekomu jinemu)
- a od te doby bychom nemeli predpokladat, ze v tom objektu budou smysluplna data (u toho, kdo to predal)
- memory leaky (program by nemel leakovat ani na vstupech, ktere nejsou testovany)
- reseni (vetsinou): pouzivat smart pointery:
unique_ptr
, shared_ptr
- a krome smart pointeru, pouzivat standardni kontejnery
- unique je lepsi nez shared; shared pouzit tehdy, kdyz unique nedava smysl (ta struktura neni nutne stroma)
- caste opakovani stejneho (podobneho) kusu kodu
- ten kus kodu patri do funkce
- na cviceni jsme videli demonstraci toho proc
- mega dlouhe funkce, funkce delajici vic nezavislych ukonu
- proste z rozumne dlouhych casti te funkce udelejte samostatne pomocne funkce
- ty pomocne funkce se vam navic mohou hodit na to, abyste se vyhli chybe s castym opakovanim
- global state ← jakykoliv state radsi davejte do trid
- funkce, ktere pracuji na tom stavu, tak z nich udelejte metody te tridy
- skryte bugy (program by nemel failovat ani na vstupech, ktere nejsou testovany)
- nejhorsimi z nich jsou undefined behavior: veci, pro ktere neni definovano chovani
- ruzne hnusy pri pouziti
reinterpret_cast
(ten muze byt zavolan tzv. C-style castem; proto radeji pouzivejte static_cast
nebo dynamic_cast
)- reinterpret cast mate basically zakazany, takze ho radsi odnikud nekopirujte
- sahani mimo boundaries objektu (u vectoru se tomu lze vyhnout pouzitim metody
at
, ale vzdy je to treba nejdrive zhodnotit, jestli je v danem miste opravdu potreba)- vetsinou nas pred tadytim ochrani iteratory (vzdycky kontrolovat s
container.end()
- napriklad po findu; az na pripady, kdy takova kontrola nedava smysl)
- jeste silnejsi ochranu nam poskytne
#include <algorithm>
a pouzivani standardnich algoritmu namisto rucniho programovani - to casto i muze docela dost zrychlit implementaci - nemusi byt spatny napad si pred zkouskou projit seznam standardnich algoritmu pro prehled toho, co nam C++ poskytuje- ale urcite nebude velka chyba rucne napsat neco, na co existuje nejaky std:: algoritmus, spis to je jen zbytecne ztraceny cas
- chyby v logice algoritmu - algoritmus budto neplni zadani, nebo ho plni jen nahodou
- testy typicky nemuzou kontrolovat kazdy corner case, takze za to nekdy muzete ztratit body i po rucni kontrole
- neefektivita
- zbytecny pointer: vec visi na
unique_ptr
ackoli neni polymorfni, existuje vzdy (pokud ne, stale existuje std::optional
, ktery je efektivnejsi nez pointer), neni sharovana, a sama uklada svoje data na haldu; proste treba std::unique_ptr<std::vector<int>>
- pokud neni duvod, proc by to melo byt v pointeru, tak by to nemelo byt v pointeru
- pocitani veci dvakrat zbytecne:
for (std::size_t i = 0; i < vec.size(); ++i) ... vec.at(i) ...
(at
dela zbytecny bounds check - prochazime jen validni indexy, takze proc checkovat znovu?)
if (!container.contains(k)) container.insert(k);
- na tenhle pattern postaci klidne jenom insert (vraci, jestli se insertovalo = true
, nebo jestli to tam uz bylo = false
)
- spatna volba kontejneru, napr.: pokud si chceme zaznamenat nejake prvky a potom zjistovat, jestli mame nejaky takovy zaznamenany, tak nejspise nebude dobra volba si je ukladat v
std::list
(nejspise bychom pouzili std::(unordered_)set
; nebo setrideny std::vector
a std::binary_search
z <algorithm>
)
- veci, ktere do C++ nepatri nebo se s nimi musi zachazet hodne specifickym zpusobem
new
, delete
, raw pointery (object*
) jako vlastnici pameti ← za to se bude nejspis opravdu vyhazovat; new a delete nejsou nutne smrtelnou chybou, ale casto jde jejich pouziti nahradit napr. std::make_unique
, ktere je mnohem jednodussi na praci (nemusime myslet na delete) a bezpecnejsi
using namespace
(hlavne v headeru) ← nekteri cvicici to nemaji radi; samozrejme pokud se jim nebude libit KONKRETNE using namespace std
v .cpp souborech a strhnou za to body, tak to kontroluji blbe; podobne treba using namespace std::chrono_literals
v konkretnim scopu (ve funkci treba) - to je standard practice
- (obecne) konstrukty z C, ktere maji C++ ekvivalent (napr Cckovy
NULL
namisto nullptr
, printf, …)
- extremne low-level praktiky, pokud jsou pouzity spatne (typicky aritmetika na pointerech, bitwise aritmetika na cislech, …)
- obecne se nebudou strhavat body za spatny styl ani za drobnou necitelnost, ani za zvoleni neoptimalniho reseni (ale zde jen do urcite meze; stale se pocita s tim, ze si pamatujete aspon big-O notaci), pokud nelze jednoduse zefektivnit (viz vyse; napr predavanim referenci namisto hodnoutou)
- Budou se jenom malo strhavat body za spatny design, ale urcite se mu vyhybejte; priklady bad designu:
- v reseni jsou nejasne dependence mezi ruznyma kusama kodu (tzv spaghetti code)
- (veci maji zavadejici nazvy nebo maji nejasny ucel)