Ein Array von Objekten mit memset() initialisieren?



  • Kurz zur Vorgeschichte: In einem Spiel hat jedes Objekt eine x/y-Position. Um schnell herauszufinden, ob eine bestimmte Position frei (= 0) oder von einem Objekt belegt ist (!= 0), sammle ich die Objekte zusätzlich in einer zweidimensionalen Matrix. Etwa so:

    // Deklaration
    SpielObjekt ***matrix;
    // Erste Initialisierung
    matrix = new SpielObjekt **[256];
    for (int i = 0; i < 256; i++)
    {
      matrix[i] = new SpielObjekt *[256];
    }
    

    Beim Wechsel in den nächsten Level will ich diesen Speicher nicht umständlich freigeben und neu reservieren, sondern ihn nur zurücksetzen. So funktioniert es:

    // Matrix leer machen
    for (int y = 0; y < 256; y++)
    {
      for (int x = 0; x < 256; x++)
      {
        matrix[x][y] = 0;
      }
    }
    

    Meine Frage: Geht das schneller? Vielleicht mit memset()?



  • Mit memset(..) geht es schneller.
    Die ist aber nur in ganz wenigen spezial Fällen wirklich erlaubt.
    Wenn Du mit POD's arbeitest sollte es keine Probleme geben. Ich würde denoch von dieser Idee abraten (ist gefährlich). Sieht auch ein wenig na premature optimization aus.

    Simon

    Edit: Ausserdem würde ich in Betracht ziehen std::vector als Container zu verwenden.



  • simon.gysi schrieb:

    .. ist aber nur in ganz wenigen spezial Fällen wirklich erlaubt...

    in c/c++ ist memset grundsätzlich immer erlaubt.



  • Ok, und wie wäre es richtig?

    memset(matrix, 0, sizeof(SpielObjekt) * 256 * 256); //So bestimmt nicht, oder?
    memset(matrix, 0, sizeof(matrix) * 256 * 256); //So?
    memset(matrix, 0, sizeof(matrix)); //So?
    


  • loller schrieb:

    simon.gysi schrieb:

    .. ist aber nur in ganz wenigen spezial Fällen wirklich erlaubt...

    in c/c++ ist memset grundsätzlich immer erlaubt.

    *g* erlaubt schon... aber es ergibt nicht immer den gewünschten effekt... z.B. mit vtbl's...
    simon

    Edit: hier gehts ja "nur" um pointer zurücksetzten, trotzdem sollte man sich der problematik bewusst sein.


  • Mod

    mados schrieb:

    Ok, und wie wäre es richtig?

    memset(matrix, 0, sizeof(SpielObjekt) * 256 * 256); //So bestimmt nicht, oder?
    memset(matrix, 0, sizeof(matrix) * 256 * 256); //So?
    memset(matrix, 0, sizeof(matrix)); //So?
    

    Keines davon. "Schneller" ist ohne Kontext bedeutungslos und memset ungeeignet und überhaupt stellt sich die Frage, warum du nicht gleich ein
    SpielObjekt[256][256] verwendest.



  • camper schrieb:

    ... warum du nicht gleich ein SpielObjekt[256][256] verwendest.

    Weil es variabel sein soll und die 256 nur ein Beispiel ist. Unabhängig davon habt ihr mir schon sehr geholfen: Mir war nicht ganz klar, dass die Pointer in dieser Matrix (sie besteht ja nur aus Pointern) nicht mein Problem sind, sondern die Objekte.



  • die schose mit den vielen zeigern ist imho überflüssig.
    gucke mal, so kannst du vieeele zeiger sparen und damit gleichzeitig vieeel SPEED gewinnen:

    using namespace std;
    struct Loller
    {
    	int value;
    };
    typedef struct Loller Spielobjekt;
    // const ist hier nur für meine Bequemlicheit :D
    const X = 256; // TODO: variabel machen.
    const Y = 256;
    
    void SetAtXY( Spielobjekt* LOL, unsigned x, unsigned y, int value )
    {
    	( LOL + y*X + x )->value = value;
    }
    
    void ShowAtXY( Spielobjekt* LOL, unsigned x, unsigned y )
    {
    	cout << ( LOL + y*X + x )->value << endl;
    }
    int main(int argc, char* argv[])
    {
    	int egal = 88;
    	Spielobjekt* LOL = new Spielobjekt [X*Y];
    
    	memset( LOL, 0, 256*256 );
    
    	SetAtXY( LOL, 88, 88, egal );
    	ShowAtXY( LOL, 88, 88 );
    
    	delete [] LOL;
    }
    

  • Mod

    In diesem Sinne, effizient und ohne unnötigen Ballast:

    #include <boost/multi_array.hpp>
    #include <cstddef>
    using std::size_t;
    struct Foo { int value; };
    typedef boost::multi_array<Foo,2> FooArray;
    using boost::multi_array_types::index;
    
    void SetAtXY(FooArray& arr, index x, index y, int value)
    {
        arr[x][y].value = value;
    }
    
    void ShowAtXY(const FooArray& arr, index x, index y)
    {
        cout << arr[x][y].value << endl;
    }
    int main()
    {
        int X = 100;
        int Y = 100;
        FooArray arr(boost::extends[X][Y]);
    
    // zum Löschen, unnötig nach der Konstruktion:
        std::fill_n(arr.origin(), arr.numm_elements(), Foo());
    
        SetAtXY( arr, 88, 88, 42 );
        ShowAtXY( arr, 88, 88 );
    }
    

    Aus mir unverständlichen Gründen wird auf diese Lösung viel zu selten hingewiesen, dabei taucht die Problematik mehrdimensionaler Arrays hier mit schöner Regelmäßigkeit auf.



  • camper schrieb:

    In diesem Sinne, effizient und ohne unnötigen Ballast:

    #include <boost/multi_array.hpp>
    #include <cstddef>
    using std::size_t;
    struct Foo { int value; };
    typedef boost::multi_array<Foo,2> FooArray;
    using boost::multi_array_types::index;
    
    void SetAtXY(FooArray& arr, index x, index y, int value)
    {
        arr[x][y].value = value;
    }
    
    void ShowAtXY(const FooArray& arr, index x, index y)
    {
        cout << arr[x][y].value << endl;
    }
    int main()
    {
        int X = 100;
        int Y = 100;
        FooArray arr(boost::extends[X][Y]);
    
    // zum Löschen, unnötig nach der Konstruktion:
        std::fill_n(arr.origin(), arr.numm_elements(), Foo());
    
        SetAtXY( arr, 88, 88, 42 );
        ShowAtXY( arr, 88, 88 );
    }
    

    Aus mir unverständlichen Gründen wird auf diese Lösung viel zu selten hingewiesen, dabei taucht die Problematik mehrdimensionaler Arrays hier mit schöner Regelmäßigkeit auf.

    😃
    Was für eine Problematik mehrdimensionaler Arrays?
    Die Masse braucht <boost/multi_array.hpp> nicht, weils auch anders geht.



  • Oder so?

    #include <vector>
    #include <algorithm>
    
    struct Spielobject
    {
        int x;
        int y;
    };
    
    typedef std::vector< std::vector<Spielobject> > GameMatrix;
    
    void resetSpielObj(Spielobject& obj)
    {
        obj.x = 0;
        obj.y = 0;
    }
    
    void resetSubVector(std::vector<Spielobject>& subVector)
    {
        std::for_each
            ( subVector.begin()
            , subVector.end()
            , resetSpielObj );
    }
    
    void resetGame(std::vector< std::vector<Spielobject> >& gameMatrix)
    {
        std::for_each
            ( gameMatrix.begin()
            , gameMatrix.end()
            , resetSubVector );
    }
    
    int main()
    {
        GameMatrix gameMatrix(10, std::vector<Spielobject>(10));
        resetGame(gameMatrix);
        return 0;
    };
    

Anmelden zum Antworten