streda 1. júna 2011

V čom je chyba?

V jednom C++ kóde som spravil chybu a relatívne ma to prekvapilo. Aj keď po tom čo som si uvedomil, že to je chyba tak to bolo hneď zrejmé. Zjednodušene som túto chybu zaniesol do nasledujúceho kódu - nájdete chybu/chyby? Viete povedať čo sa stane bez toho aby ste spustili tento kód? A ako by ste ho opravili?

#include <string.h>

 
class A
{
public:
       A()
       {
              Initialize();
       }

      
~A()
       {
              Deinitialize();
       }

      
virtual void Initialize()
       {
       }

      
virtual void Deinitialize()
       {
       }
};
 
class B : public A
{
public:
       char *m_pMemory;
       B()
       {
              m_pMemory = NULL;
       }
 
       virtual void Initialize()
       {
              m_pMemory = new char[ 200];
              strcpy( m_pMemory, "Pekne nam to funguje\n");
       }
 
       virtual void Deinitialize()
       {
              if ( m_pMemory)
                     delete []m_pMemory;
       }
 
       char *GetMemory()
       {
              return m_pMemory;
       }
};
 
int _tmain(int argc,  _TCHAR* argv[])
{
      
B b;

      
printf( b.GetMemory());
 
       return 0;
}

6 komentárov:

  1. a) volanie virtuálne metódy v konštruktore triedy - aspoň v .NET je to neodporúčané, pretože sa môže zavolať zlá virtuálna metóda. Neviem ako presne funguje vtable v C++, ale myslím, že problém môže byť rovnaký.

    b) ak by sa aj B.Initialize() zavolala, tak vynulovanie pointeru nastane po Initialize() a teda stratíš referenciu a máš memory leak.

    OdpovedaťOdstrániť
  2. Ano mate v podstate pravdu - aj ked nie je to uplne spravna odpoved. Myslim, ze v jave a C# by to bola spravna odpoved - ale v C++ to je trosku ine - B::Initialize sa tu ani nezavola. V destruktore a konstruktore ked sa volaju virtualne metody tak sa beru virtualne metody z daneho classu a nie tie co by si clovek namyslal :)

    Ono ked to clovek takto vidi v exampli tak ho hned trkne - ale ak ide o obsiahlejsi kod tak tam uz je problem ...

    OdpovedaťOdstrániť
  3. No, však v .NETe to je rovnako. Sa ti nezavolá posledná prepísaná metóda. Preto je v FxCope aj pravidlo, ktoré ti takéto volania nájde a zreportuje chybu.

    OdpovedaťOdstrániť
  4. Ak som dobre pochopil z http://www.artima.com/cppsource/nevercall.html tak prave c# sa to sprava inac ako v c++. Predpokladam, ze podobne ako java...

    Aj ked to v tej jave povazujem za zvlastne - ako to funguje v jave - inicializuju sa najprv vsetky premenne a az potom idu konstruktory?

    OdpovedaťOdstrániť
  5. v c++ sa inicializuje najprv pamat pre triedu a potom sa postupne volaju construktory ktore inicializuju "svoje" premenne. Takze ak by sa volala nejaka metoda zo zdedenej classy tak by jej premenne este neboli inicializovane ...

    OdpovedaťOdstrániť
  6. cau jozo, este je chyba aj to ze A nema virtualny destruktor.

    OdpovedaťOdstrániť