První hádanka spočívala v tom, co by mohlo být špatně na následujícím kousku kódu:
typedef struct NejakaStruktura { .. };
void nejakaFunkce(NejakaStruktura nazev) { ... }
NejakaStruktura a;
nejakaFunkce(a);
Tento kód půjde zkompilovat a bude dokonce i správně fungovat. Problém nicméně spočívá v tom, že ve většině případů by byl naprosto zbytečně pomalý kvůli tomu, že předávaná struktura se bude pokaždé kopírovat. V případě velmi malých struktur (nebo tříd) by to bylo pravděpodobně jedno, ale pokud bychom se bavili například o stovkách bajtů, zpomalení by mohlo být poměrně markantní.
Na níže uvedeném příkladu je vidět, jak to udělat pomocí tzv. referencí. V mém případě byl (při konstantním zatížení systému) výsledek 42s pro foo1 a 35s pro foo2. Samozřejmě podobná měření jsou velmi ošemetná záležitost, protože záleží na přesné konfiguraci kompilátoru a zvolené úrovni optimalizací, ale nějakou vypovídající hodnotu přesto má.
#include
#include
#include
typedef struct TStruct
{
int values[100];
};
int foo1(TStruct someStruct)
{
int t = 0;
for (int i = 0; i < 100; i++)
t += someStruct.values[i];
return t;
}
int foo2(TStruct &someStruct)
{
int t = 0;
for (int i = 0; i < 100; i++)
t += someStruct.values[i];
return t;
}
int main(int argc, char *argv[])
{
TStruct myStruct;
for (int i = 0; i < 100; i++)
myStruct.values[i] = i;
int t0 = time(NULL);
for (int i = 0; i < 50000000; i++)
foo1(myStruct);
int t1 = time(NULL);
for (int i = 0; i < 50000000; i++)
foo2(myStruct);
int t2 = time(NULL);
printf(\"Foo1: %i\\n\", t1 - t0);
printf(\"Foo2: %i\\n\", t2 - t1);
return EXIT_SUCCESS;
}
Druhá hádanka byla, jak inicializovat hodnotu const atributu třídy. V C++, narozdíl například od Javy, nelze hodnotu přiřadit rovnou při deklaraci atributu na témže řádku. Pokud by atribut nebyl označen modifikátorem const, bylo by možné jej inicializovat v libovolné metodě, nejčastěji pravděpodobně v konstruktoru. Nebudu vás již napínat, správná syntaxe vypadá takto:
class Foo
{
public:
Foo() :
m_Value(0)
{
//
}
private:
const int m_Value;
};
Tímto způsobem lze samozřejmě inicializovat všechny atributy, nikoliv pouze konstanty.
Poslední hádanka se týkala rozdílů při odchytávání výjimek vyvržených prvním a druhým způsobem.
//#1:
throw new Exception;
//#2:
Exception exception;
throw exception;
Rozdíl je v tomto případě naprosto zásadní. V prvním případě by byl vyvržen ukazatel. Abyste tedy výjimku mohli odchytit, museli byste rovněž v catch konstrukci uvést, že se jedná o ukazatel. Pokud by programátor nějaké knihovny použil právě tento (špatný) způsob a uživatel knihovny výjimku odchytával s předpokladem, že byla vyvržena pomocí druhého způsobu, program by mu při vyvržení výjimky spadl - vůbec by se neodchytla. V catch konstrukci by totiž byl uveden zcela jiný typ, než jaký výjimka ve skutečnosti měla. Další problém spočívá v tom, že v prvním případě by programátor musel myslet na to, aby po odchycení výjimky provedl její dealokaci pomocí operátoru delete.
Zajímavostí oproti jiným jazycím je to, že výjimky v C++ nemají žádný předepsaný typ a dokonce i konstrukce jako je tato bude validní.
int i = 5;
throw i;
Chraň vás mozek toto někde použít!Můžete si prohlédnout ještě zdrojový kód, který demonstruje rozdíly při odchytávání výjimek jedním či druhým způsobem.
#include
class Exception{};
int main(int argc, char *argv[])
{
try
{
throw new Exception;
}
catch (Exception *exception)
{
puts(\"Odchyceno #1\");
// exception->getErrorMessage()
delete exception;
}
try
{
Exception exception;
throw exception;
}
catch (Exception exception)
{
puts(\"Odchyceno #2\");
// exception.getErrorMessage()
}
}
Tento článek si nekladl za cíl šířit žádná zásadní moudra, ale naznačit (poměrně banální) problémy, které vás v C++ mohou potkat. Domnívám se, že pro řadu začátečníků jsou tyto skutečnosti poměrně skryté a toto by pro ně tedy mělo být jen jakési základní nakopnutí. Zároveň mi přislo hloupé nahodit v diskuzi nějakou problematiku a nechat ji zcela bez odpovědi.
Ačkoliv článek nese v titulku "#1", neznamená to, že na něj budou navazovat další - ačkoliv vyloučené to není. Pokud by o to byl zájem, zvážil bych napsání něčeho dalšího.
PS: Tento článek píšu ve spěchu a navíc se za žádného velkého odborníka na C++ rozhodně nepovažuji, proto je možné, že v něm budou faktické či jiné chyby. Pokud si něčeho takového všimnete, nestyďte se upozornit mě na to v komentářích, rád chybu opravím.
Aktualizace: Díky upozornění Bystroushaaka byl článek upraven tak, aby používal zvýrazňovač syntaxe.