Zpět na seznam článků     Číst komentáře (11)     Verze pro tisk

Něco málo z C++ #1

Autor: independent   
13.3.2013

V diskuzi jsem zde nahodil několik hádanek z C++, na které pravděpodobně většina začátečníků nebude znát odpověď. Aby vysvětlení nezapadlo kdesi v hlubinách diskuze, vkládám to jako user text.


Předávání struktury parametrem

První hádanka spočívala v tom, co by mohlo být špatně na následujícím kousku kódu:

  1. typedef struct NejakaStruktura { .. };
  2. void nejakaFunkce(NejakaStruktura nazev) { ... }
  3.  
  4. NejakaStruktura a;
  5. 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á.

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <ctime>
  4.  
  5. typedef struct TStruct
  6. {
  7.         int values[100];
  8. };
  9.  
  10. int foo1(TStruct someStruct)
  11. {
  12.         int t = 0;
  13.         for (int i = 0; i < 100; i++)
  14.                 t += someStruct.values[i];
  15.  
  16.         return t;
  17. }
  18.  
  19. int foo2(TStruct &someStruct)
  20. {
  21.         int t = 0;
  22.         for (int i = 0; i < 100; i++)
  23.                 t += someStruct.values[i];
  24.  
  25.         return t;
  26. }
  27.  
  28. int main(int argc, char *argv[])
  29. {
  30.         TStruct myStruct;
  31.         for (int i = 0; i < 100; i++)
  32.                 myStruct.values[i] = i;
  33.  
  34.         int t0 = time(NULL);
  35.         for (int i = 0; i < 50000000; i++)
  36.                 foo1(myStruct);
  37.  
  38.         int t1 = time(NULL);
  39.         for (int i = 0; i < 50000000; i++)
  40.                 foo2(myStruct);
  41.  
  42.         int t2 = time(NULL);
  43.  
  44.         printf(\"Foo1: %i\\n\", t1 - t0);
  45.         printf(\"Foo2: %i\\n\", t2 - t1);
  46.  
  47.         return EXIT_SUCCESS;
  48. }

Inicializace atributů

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:

  1. class Foo
  2. {
  3.         public:
  4.                 Foo() :
  5.                         m_Value(0)
  6.                 {
  7.                         //
  8.                 }
  9.  
  10.         private:
  11.                 const int m_Value;
  12. };

Tímto způsobem lze samozřejmě inicializovat všechny atributy, nikoliv pouze konstanty.

Výjimky

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. //#1:
  2. throw new Exception;
  3.  
  4. //#2:
  5. Exception exception;
  6. 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í.

  1. int i = 5;
  2. 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.

  1. #include <cstdio>
  2.  
  3. class Exception{};
  4.  
  5. int main(int argc, char *argv[])
  6. {
  7.         try
  8.         {
  9.                 throw new Exception;
  10.         }
  11.         catch (Exception *exception)
  12.         {
  13.                 puts(\"Odchyceno #1\");
  14.                 // exception->getErrorMessage()
  15.                 delete exception;
  16.         }
  17.  
  18.         try
  19.         {
  20.                 Exception exception;
  21.                 throw exception;
  22.         }
  23.         catch (Exception exception)
  24.         {
  25.                 puts(\"Odchyceno #2\");
  26.                 // exception.getErrorMessage()
  27.         }
  28. }

Závěr

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.


Líbil se Vám článek?
Budeme potěšeni, pokud vás zaujme také reklamní nabídka

Social Bookmarking

     





Hodnocení/Hlasovalo: 2/1

1  2  3  4  5    
(známkování jako ve škole)