C++ probléma

Kezdőlap Fórumok Programozás C++ probléma

10 bejegyzés megtekintése - 1-10 / 13
  • Szerző
    Bejegyzés
  • #2139152
    pointux
    Felhasználó

      Helyesen így néz ki a kód:

      Code:
      class Vector3D {
        /* … */
      }

      Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) {
        Vector3D * _dst = NULL;

        try {
          _dst = new Vector3D ( /* … */ );
        } catch ( /* … */ ) {
          /* … */
        }

        std::auto_ptr __dst ( _dst ); // (1)
        /* … */

        return * _dst;
      }

      Az (1) nélkül szivárgás következhet be a következő esetben:

      Code:
      Vector3D _v_dst;

      _v_dst = _v_src1 * _v_src2;

      A szivárgás, persze elkerülhető így:

      Code:
      Vector3D *_v_dst;

      _v_dst = &_v_src1 * _v_src2;

      delete _v_dst;

      Az (1) esetében az egyébként szükségtelen delete operátor kiadása után nullázni kell a pointert:

      Code:
      Vector3D * _v_dst

      delete _v_dst;
      _v_dst = NULL;

      mert máskülönben a létrehozott Vector3D objektumon az „élettartam-lejárta” után a program megpróbálja lefuttatni rajta a free függvényt. Ez azért kellemetlen, mert a fent említett memória mutató egy már felszabadított területre mutat.
      Persze nem lenne gond, ha a C nyelv biztonságosabbra lenne írva…
      Ennyi már elég lenne:

      Code:
      void delete ( void ** _ptr)

      Mert így már lehetne nullázni. (Noha ez fél megoldás, mert lehetne mutató mutatója is.)

      Persze az „stl” is meg lehetett volna normálisan írni, mert nem ez az egy eset, ami azonnal feloldatlan kivételt okoz… úgyhogy mindenki azt tanítja, de aki ad magára nem használja, legfeljebb feltételekkel.

      #2139153
      pointux
      Felhasználó

        Helyesen így néz ki a kód:

        Code:
        class Vector3D {
          /* … */
        }

        Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) {
          Vector3D * _dst = NULL;

          try {
            _dst = new Vector3D ( /* … */ );
          } catch ( /* … */ ) {
            /* … */
          }

          std::auto_ptr __dst ( _dst ); // (1)
          /* … */

          return * _dst;
        }

        Az (1) nélkül szivárgás következhet be a következő esetben:

        Code:
        Vector3D _v_dst;

        _v_dst = _v_src1 * _v_src2;

        A szivárgás, persze elkerülhető így:

        Code:
        Vector3D *_v_dst;

        _v_dst = &_v_src1 * _v_src2;

        delete _v_dst;

        Az (1) esetében az egyébként szükségtelen delete operátor kiadása után nullázni kell a pointert:

        Code:
        Vector3D * _v_dst

        delete _v_dst;
        _v_dst = NULL;

        mert máskülönben a létrehozott Vector3D objektumon az „élettartam-lejárta” után a program megpróbálja lefuttatni rajta a free függvényt. Ez azért kellemetlen, mert a fent említett memória mutató egy már felszabadított területre mutat.
        Persze nem lenne gond, ha a C nyelv biztonságosabbra lenne írva…
        Ennyi már elég lenne:

        Code:
        void delete ( void ** _ptr)

        Mert így már lehetne nullázni. (Noha ez fél megoldás, mert lehetne mutató mutatója is.)

        Persze az „stl” is meg lehetett volna normálisan írni, mert nem ez az egy eset, ami azonnal feloldatlan kivételt okoz… úgyhogy mindenki azt tanítja, de aki ad magára nem használja, legfeljebb feltételekkel.

        #2139154
        gabaman
        Felhasználó
          FLINX wrote:
          Üdv.

          Csatoltam egy C++ kódot, amire a g++ a következő hibaüzenetet adja:

          Code:
          test.cpp: In member function ‘bool Sphere::Intersect(const Ray&, HitRec*)’:
          test.cpp:74: error: passing ‘const Vector3D’ as ‘this’ argument of ‘Vector3D Vector3D::operator-(Vector3D)’ discards qualifiers
          test.cpp:76: error: passing ‘const Vector3D’ as ‘this’ argument of ‘float Vector3D::operator*(Vector3D)’ discards qualifiers
          test.cpp:97: error: passing ‘const Vector3D’ as ‘this’ argument of ‘Vector3D Vector3D::operator*(float)’ discards qualifiers
          test.cpp:97: error: passing ‘const Vector3D’ as ‘this’ argument of ‘Vector3D Vector3D::operator+(Vector3D)’ discards qualifiers

          Ami röveden annyi, hogy az említett függvényben egy konstans Vector3D objektumot nem tud átadni this argumentumként a felsorolt operátor függvényeknek…

          A C++ nyelvben ha egy objektom konstans minősítésű (itt: konstans paraméter), akkor csak a konstans metódusokat lehet elérni, jelenleg ez a baja a GCC fordítónak. Megoldás: használj ‘const’ minősítőt az objektumot nem módosító metódusoknál.

          Code:
          Vector3D operator=(const Vector3D& v); // Módosít, nem konstans metódus

          Vector3D operator+( Vector3D v) const; // Nem módosít, ‘const’ utóminősítőt kapott
          Vector3D operator-( Vector3D v) const;

          Vector3D operator*(const float f) const ;
          Vector3D operator/(const float f) const;

          float operator*(const Vector3D v) const   {return x*v.x+y*v.y+z*v.z;} //skaláris szorzat
          float Length() const   {return (float)sqrt(x*x+y*y+z*z);}
          float* GetArray() const     {return &x; } // struktúra kezdőcíme (nem kontsans objektumból meghívva)
          const float* GetArray() const   {return &x; } // struktúra kezdőcíme (konstans objektumból meghívva)

          FLINX wrote:
          A kódban máshol használom ezeket az operátor függvényeket, és arra nem jelent hibát…
          Pedig elvileg itt is ugyanolyan Vector3D illetve float argumentumokkal próbálok kiértékelni műveleteket, mint máshol.

          Ez azért van.mert a többi helyen nem konstans objektum metódusát hívod, a ‘bool Sphere::Intersect(const Ray&, HitRec*)’ metódus ‘ray’ paramétere meg konstans. Ha a fenti minősitőket hsználod, akkor már nem lesz gond.

          #2139155
          gabaman
          Felhasználó
            FLINX wrote:
            Üdv.

            Csatoltam egy C++ kódot, amire a g++ a következő hibaüzenetet adja:

            Code:
            test.cpp: In member function ‘bool Sphere::Intersect(const Ray&, HitRec*)’:
            test.cpp:74: error: passing ‘const Vector3D’ as ‘this’ argument of ‘Vector3D Vector3D::operator-(Vector3D)’ discards qualifiers
            test.cpp:76: error: passing ‘const Vector3D’ as ‘this’ argument of ‘float Vector3D::operator*(Vector3D)’ discards qualifiers
            test.cpp:97: error: passing ‘const Vector3D’ as ‘this’ argument of ‘Vector3D Vector3D::operator*(float)’ discards qualifiers
            test.cpp:97: error: passing ‘const Vector3D’ as ‘this’ argument of ‘Vector3D Vector3D::operator+(Vector3D)’ discards qualifiers

            Ami röveden annyi, hogy az említett függvényben egy konstans Vector3D objektumot nem tud átadni this argumentumként a felsorolt operátor függvényeknek…

            A C++ nyelvben ha egy objektom konstans minősítésű (itt: konstans paraméter), akkor csak a konstans metódusokat lehet elérni, jelenleg ez a baja a GCC fordítónak. Megoldás: használj ‘const’ minősítőt az objektumot nem módosító metódusoknál.

            Code:
            Vector3D operator=(const Vector3D& v); // Módosít, nem konstans metódus

            Vector3D operator+( Vector3D v) const; // Nem módosít, ‘const’ utóminősítőt kapott
            Vector3D operator-( Vector3D v) const;

            Vector3D operator*(const float f) const ;
            Vector3D operator/(const float f) const;

            float operator*(const Vector3D v) const   {return x*v.x+y*v.y+z*v.z;} //skaláris szorzat
            float Length() const   {return (float)sqrt(x*x+y*y+z*z);}
            float* GetArray() const     {return &x; } // struktúra kezdőcíme (nem kontsans objektumból meghívva)
            const float* GetArray() const   {return &x; } // struktúra kezdőcíme (konstans objektumból meghívva)

            FLINX wrote:
            A kódban máshol használom ezeket az operátor függvényeket, és arra nem jelent hibát…
            Pedig elvileg itt is ugyanolyan Vector3D illetve float argumentumokkal próbálok kiértékelni műveleteket, mint máshol.

            Ez azért van.mert a többi helyen nem konstans objektum metódusát hívod, a ‘bool Sphere::Intersect(const Ray&, HitRec*)’ metódus ‘ray’ paramétere meg konstans. Ha a fenti minősitőket hsználod, akkor már nem lesz gond.

            #2139156
            gabaman
            Felhasználó
              vizsla wrote:
              Helyesen így néz ki a kód:

              Code:
              class Vector3D {
                /* … */
              }

              Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) {
                Vector3D * _dst = NULL;

                try {
                  _dst = new Vector3D ( /* … */ );
                } catch ( /* … */ ) {
                  /* … */
                }

                std::auto_ptr __dst ( _dst ); // (1)
                /* … */

                return * _dst;
              }

              Ha feladjuk a szálbiztos felépítést, akkor egyszerűbb és hatékonyabb ez a kód:

              Code:
              class Vector3D {
                /* … */
              }

              Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) {
                static Vector3D _dst;

                /* … */

                return  _dst;
              }

              De így se kerülhetjük el a visszatérési érték egyenkénti másolgatását, hacsak nem használunk tömböt az egyenkénti vagy csoportos műveletekhez:

              Code:
              // Absztakt osztály
              class Vector3D {
                public:
                  virtual ~Vector3D ();

                  virtual Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) const=0;
              };

              // A klasszikus Vector3D implementáció; független
              class Vector3DStatic: public Vector3D {
                private:
                  float x;
                  float y;
                  float z;
                public:
                  virtual ~Vector3DStatic ();

                  virtual Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) const;
                  Vector3DStatic operator* ( const Vector3DStatic & _src1, const Vector3DStatic & _src2 ) const;
              };

              // Egy Vector3D tömb eleme, függ a tömbtöl, de viszont gyors és hatékony
              class Vector3DArrayItem: public Vector3D {
                private:
                  float *item;  // float triplet, mutató a Vector3DArray::store egyik elemére
                public:
                  virtual ~Vector3DArrayItem ();

                  virtual Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) const;
                  Vector3DArrayItem operator* ( const Vector3DArrayItem & _src1, const Vector3DArrayItem & _src2 ) const;
              };

              // A Vector3D tömb implementációja
              class Vector3DArray {
                private:
                  size_t size;
                  float *store;  // Hossz: size*3;
                public:
                  Vector3DArray (size_t _size);
                ~Vector3DArray ();

                  Vector3DArrayItem operator[] (size_t _pos) const;
                  float[3] raw (size_t _pos);
                  Vector3DArray operator* ( const Vector3DArray & _src1, const Vector3DArray & _src2 ) const;
                  Vector3DArray subarray (size_t _start size_t _end) const;
              };

              #2139157
              gabaman
              Felhasználó
                vizsla wrote:
                Helyesen így néz ki a kód:

                Code:
                class Vector3D {
                  /* … */
                }

                Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) {
                  Vector3D * _dst = NULL;

                  try {
                    _dst = new Vector3D ( /* … */ );
                  } catch ( /* … */ ) {
                    /* … */
                  }

                  std::auto_ptr __dst ( _dst ); // (1)
                  /* … */

                  return * _dst;
                }

                Ha feladjuk a szálbiztos felépítést, akkor egyszerűbb és hatékonyabb ez a kód:

                Code:
                class Vector3D {
                  /* … */
                }

                Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) {
                  static Vector3D _dst;

                  /* … */

                  return  _dst;
                }

                De így se kerülhetjük el a visszatérési érték egyenkénti másolgatását, hacsak nem használunk tömböt az egyenkénti vagy csoportos műveletekhez:

                Code:
                // Absztakt osztály
                class Vector3D {
                  public:
                    virtual ~Vector3D ();

                    virtual Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) const=0;
                };

                // A klasszikus Vector3D implementáció; független
                class Vector3DStatic: public Vector3D {
                  private:
                    float x;
                    float y;
                    float z;
                  public:
                    virtual ~Vector3DStatic ();

                    virtual Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) const;
                    Vector3DStatic operator* ( const Vector3DStatic & _src1, const Vector3DStatic & _src2 ) const;
                };

                // Egy Vector3D tömb eleme, függ a tömbtöl, de viszont gyors és hatékony
                class Vector3DArrayItem: public Vector3D {
                  private:
                    float *item;  // float triplet, mutató a Vector3DArray::store egyik elemére
                  public:
                    virtual ~Vector3DArrayItem ();

                    virtual Vector3D operator* ( const Vector3D & _src1, const Vector3D & _src2 ) const;
                    Vector3DArrayItem operator* ( const Vector3DArrayItem & _src1, const Vector3DArrayItem & _src2 ) const;
                };

                // A Vector3D tömb implementációja
                class Vector3DArray {
                  private:
                    size_t size;
                    float *store;  // Hossz: size*3;
                  public:
                    Vector3DArray (size_t _size);
                  ~Vector3DArray ();

                    Vector3DArrayItem operator[] (size_t _pos) const;
                    float[3] raw (size_t _pos);
                    Vector3DArray operator* ( const Vector3DArray & _src1, const Vector3DArray & _src2 ) const;
                    Vector3DArray subarray (size_t _start size_t _end) const;
                };

                #2139158
                pointux
                Felhasználó

                  1) Két jobboldali operandust kívánó kifejezésnél egyébként sem praktikus, ha a függvény tag (legfeljebb barát lehet). Gondolj csak bele egy ilyen kifejezésre v3d operator* ( float, v3d ), vagy akár v3d operator* ( v3d , v3d ). Ezeknél a típusú kifejezéseknél gond van, akár definiálsz egy const visszatérési értéket, akár egy const konvertálást hajtasz végre.

                  2) Persze nem kell dinamikusan létrehozni. (Bár ez szabad memória kérdése.)
                  Szerintem a legpraktikusabb paraméterként is referencia pointert használni. (Az operátor miatt itt nem „lehet”.)

                  3) Egy statikus adat miatt nem kell felmondani a szálbiztos működést. Csak kell egy statikus jelző bit.

                  Code:
                  if ( …::guard_bit == true ) {
                    /* Most nem férek hozzá… várni kell!*/
                  } {
                    …::guard_bit = true; // most a többiek várnak
                    /* … */
                    …::guard_bit = false; // most már szabad az út
                  }

                  Persze kérdés, hogy ebben az esetben van-e értelme a több szálnak. Ebben az esetben van:

                  Code:
                  if ( …::guard_bit == true ) {
                    /* Most nem férek hozzá… várni kell!*/
                  } {
                    …::guard_bit = true; // most a többiek várnak
                    /* Én pedig regisztrálom magam egy globális statikus listán, hogy ki vagyok és mennyi memóriát foglalok.
                      És ehhez az információhoz bárki hozzáférhet. */
                    …::guard_bit = false; // most már szabad az út
                  }
                  #2139159
                  pointux
                  Felhasználó

                    1) Két jobboldali operandust kívánó kifejezésnél egyébként sem praktikus, ha a függvény tag (legfeljebb barát lehet). Gondolj csak bele egy ilyen kifejezésre v3d operator* ( float, v3d ), vagy akár v3d operator* ( v3d , v3d ). Ezeknél a típusú kifejezéseknél gond van, akár definiálsz egy const visszatérési értéket, akár egy const konvertálást hajtasz végre.

                    2) Persze nem kell dinamikusan létrehozni. (Bár ez szabad memória kérdése.)
                    Szerintem a legpraktikusabb paraméterként is referencia pointert használni. (Az operátor miatt itt nem „lehet”.)

                    3) Egy statikus adat miatt nem kell felmondani a szálbiztos működést. Csak kell egy statikus jelző bit.

                    Code:
                    if ( …::guard_bit == true ) {
                      /* Most nem férek hozzá… várni kell!*/
                    } {
                      …::guard_bit = true; // most a többiek várnak
                      /* … */
                      …::guard_bit = false; // most már szabad az út
                    }

                    Persze kérdés, hogy ebben az esetben van-e értelme a több szálnak. Ebben az esetben van:

                    Code:
                    if ( …::guard_bit == true ) {
                      /* Most nem férek hozzá… várni kell!*/
                    } {
                      …::guard_bit = true; // most a többiek várnak
                      /* Én pedig regisztrálom magam egy globális statikus listán, hogy ki vagyok és mennyi memóriát foglalok.
                        És ehhez az információhoz bárki hozzáférhet. */
                      …::guard_bit = false; // most már szabad az út
                    }
                    #2139160
                    gabaman
                    Felhasználó
                      vizsla wrote:
                      1) Két jobboldali operandust kívánó kifejezésnél egyébként sem praktikus, ha a függvény tag (legfeljebb barát lehet). Gondolj csak bele egy ilyen kifejezésre v3d operator* ( float, v3d ), vagy akár v3d operator* ( v3d , v3d ). Ezeknél a típusú kifejezéseknél gond van, akár definiálsz egy const visszatérési értéket, akár egy const konvertálást hajtasz végre.

                      Mind igaz, de a konkrét példa nem tartalmaz sablont, így számomra nem volt lényeges a fenti probléma. Mivel a 3D-s alkalmazások 99,9%-a nem használ mást csak a float típust koordináták esetében, nincs is értelme sablonként megvalósítani a v3d osztályt.

                      vizsla wrote:
                      2) Persze nem kell dinamikusan létrehozni. (Bár ez szabad memória kérdése.)
                      Szerintem a legpraktikusabb paraméterként is referencia pointert használni. (Az operátor miatt itt nem „lehet”.)

                      Szerintem meg a legpraktikusabb a D nyelv garbage collector képességének használata. 🙂 Így a kódot sem kell különösebben portolni.
                      http://www.digitalmars.com/d/

                      vizsla wrote:
                      3) Egy statikus adat miatt nem kell felmondani a szálbiztos működést. Csak kell egy statikus jelző bit.

                      A statikus jelzőbittel nem használhatsz két szálnál többet, mert a jelzőbit módosításakor nem kívánt versengés léphet fel.

                      Code:
                      if ( pthread_spinlock_trylock ( …::guard_bit ) != 0 ) {
                        /* Most nem férek hozzá… várni kell!*/
                      } {
                        pthread_spinlock_lock (…::guard_bit ); // most a többiek várnak
                        /* … */
                        pthread_spinlock_unlock ( …::guard_bit ); // most már szabad az út
                      }
                      #2139161
                      gabaman
                      Felhasználó
                        vizsla wrote:
                        1) Két jobboldali operandust kívánó kifejezésnél egyébként sem praktikus, ha a függvény tag (legfeljebb barát lehet). Gondolj csak bele egy ilyen kifejezésre v3d operator* ( float, v3d ), vagy akár v3d operator* ( v3d , v3d ). Ezeknél a típusú kifejezéseknél gond van, akár definiálsz egy const visszatérési értéket, akár egy const konvertálást hajtasz végre.

                        Mind igaz, de a konkrét példa nem tartalmaz sablont, így számomra nem volt lényeges a fenti probléma. Mivel a 3D-s alkalmazások 99,9%-a nem használ mást csak a float típust koordináták esetében, nincs is értelme sablonként megvalósítani a v3d osztályt.

                        vizsla wrote:
                        2) Persze nem kell dinamikusan létrehozni. (Bár ez szabad memória kérdése.)
                        Szerintem a legpraktikusabb paraméterként is referencia pointert használni. (Az operátor miatt itt nem „lehet”.)

                        Szerintem meg a legpraktikusabb a D nyelv garbage collector képességének használata. 🙂 Így a kódot sem kell különösebben portolni.
                        http://www.digitalmars.com/d/

                        vizsla wrote:
                        3) Egy statikus adat miatt nem kell felmondani a szálbiztos működést. Csak kell egy statikus jelző bit.

                        A statikus jelzőbittel nem használhatsz két szálnál többet, mert a jelzőbit módosításakor nem kívánt versengés léphet fel.

                        Code:
                        if ( pthread_spinlock_trylock ( …::guard_bit ) != 0 ) {
                          /* Most nem férek hozzá… várni kell!*/
                        } {
                          pthread_spinlock_lock (…::guard_bit ); // most a többiek várnak
                          /* … */
                          pthread_spinlock_unlock ( …::guard_bit ); // most már szabad az út
                        }
                      10 bejegyzés megtekintése - 1-10 / 13
                      • Be kell jelentkezni a hozzászóláshoz.