Hilfe! Member-Konstanten gleich als Feldindex?
-
Folgendes geht nicht mit dem VC++.
class Terrain : public Object { public: Terrain(float x, float y, float z, int area, int size) : Object(x, y, z), _AREA_SIZE(area) { }; private: const int _AREA_SIZE; float _height_field[_AREA_SIZE][_AREA_SIZE]; };
Fehler:
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : error C2327: 'Terrain::_AREA_SIZE' : Element der einschliessenden Klasse ist kein Typname, nicht statisch und keine Aufzählung
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : error C2065: '_AREA_SIZE' : nichtdeklarierter Bezeichner
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : error C2057: Konstanter Ausdruck erwartet
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : error C2327: 'Terrain::_AREA_SIZE' : Element der einschliessenden Klasse ist kein Typname, nicht statisch und keine Aufzählung
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : error C2057: Konstanter Ausdruck erwartet
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : error C2087: '<unbekannt>' : Feldindex fehlt
e:\spieleentwicklungprogramming\projecte\engine\object.h(25) : warning C4200: Nicht dem Standard entsprechende Erweiterung : Null-Feld in Struktur/UnionNunja, ich denk mal was ich will, ist offensichtlich. Sobald ich die Zeile mit dem height_field entferne, gehts dank der Initialisierungsliste ja auch wunderbar, aber ich hätte doch gerne mein Array entsprechend groß...
Bin gespannt auf Antworten
-
Hi,
vermeide Unterstrich gefolgt von einem Großbuchstaben, das ist nur für die Standardheader selbst erlaubt.
MfG MAV
-
Hallo,
warum nimmst du keinen vector?
-
Feldgrößen die du nicht dynamisch (mit new) anlegst müssen zur kompilezeit bekannt sein. (wie es in dutzenden anderen beiträgen schon beschrieben wurde)
_AREA_SIZE wird im Konstruktor initialisiert und ist somit nicht zur kompilezeit bekannt.
Gruß Mirauder Mo
-
Ich denke wenn die Dimensionen des _height_field Arrays dynamisch sein müssen kannst du die Größe nur im Konstruktor festlegen. also zb statt
float _height_field[_AREA_SIZE][_AREA_SIZE];
machst du
float **_height_field;
und reservierst den Speicher für das Array im Konstruktor
also:_height_field = new float*[_AREA_SIZE]; for(int i = _AREA_SIZE-1; i >= 0; --i) __height_field[i] = new float[_AREA_SIZE];
-
@Mis2com: Ok, geändert.
@CarstenJ: Würd ich ja gerne, aber geht das in 2d? Und so, dass ich nicht oder nur unwesentlich mehr Speicher benötige?
@Mirauder_Mo: Hab ich mir schon gedacht
@spk101: Cool, danke, das kompiliert ohne Fehler. Aber kann ich das jetzt auch richtig mit dem 2d-Index([][]) verwenden wie ein normales Array? Kann das jetzt nämlich nicht mal eben testen, das werde ich erst später merken.
-
Für sowas schreibt man sich am besten eine Klasse die das 2dim Array kapselt.
-
spl@t schrieb:
@CarstenJ: Würd ich ja gerne, aber geht das in 2d? Und so, dass ich nicht oder nur unwesentlich mehr Speicher benötige?
vector<vector<>> braucht nicht spürbar mehr als verschachteltes new[]. Viel besser wäre es unabhängig vom Container, einen eindimensionalen zu nehmen und die "Zweidimensionalität" dann selbst reinzuinterpretieren. Als Größe width * height nehmen und dann arr[y * width + x] statt arr[x][y] verwenden. Das spart vermutlich eine Menge Speicherverwaltungsinformationen.
Dann ist der vector auch nur so minimal teurer als new[]/delete[], dass man nicht mehr viel gegen seine Vorteile sagen kann
-
Hmpf, zu spät
Habs jetzt schon so gemacht:template <class T> class Array2d { public: Array2d(int iquad) : _size(iquad) { _values = new T*[iquad]; for(int i =0; i < iquad; ++i) _values[i] = new T[iquad]; } ~Array2d() { delete[] _values; } const T& getValue(int i, int j) const { return _values[i][j]; } void setValue(int i, int j, T value) { _values[i][j]=value; } const int getSize() const {return _size;} private: T** _values; int _size; };
-
Die Klasse gibt im Destruktor nur das Zeigerarray frei, nicht die Werte. Außerdem gibt es Speicherfehler, wenn verschieden Array2ds zuweist oder kopiert -> Lieblingsbuch.
Ich wäre für ungefähr das hier:
template<typename T> class area { std::size_t width_, height_; std::vector<T> buf_; public: area(std::size_t width = 0, std::size_t height = 0, const T& init = T()) : width_(width), height_(height), buf_(width * height, init) { } // Destruktor, Kopierkonstruktor und Zuweisungsoperator entfallen dank vector const T& operator()(std::size_t x, std::size_t y) const { return buf_[y * width_ + x]; } T& operator()(std::size_t x, std::size_t y) { return buf_[y * width_ + x]; } std::size_t width() const { return width_; } std::size_t height() const { return height_; } };
Natürlich kann man da noch fleißig erweitern, aber das sollte schonmal sicherer und effizienter sein.
-
Es stimmt nicht das die Feldgröße zu Kompilezeit feststehen muss, folgendes funktioniert z.B.:
void foo(int bar) { char test[bar]; }
Warum das bei Funktionen aber bei Klassen nicht geht ist mir ein Rätsel.
-
Wenn du die GCC-Erweiterungen abstellst, geht das auch in Funktionen nicht mehr. Das ist kein gültiges C++. Im aktuellen C-Standard (C99) hingegen geht das.
-
Das war mir auch klar, gibts aber irgendeinen logischen Grund warum man sowas in Funktionen benutzen kann aber in Klassen nicht
Mal von der Definition abgesehen...
-
Lars schrieb:
Das war mir auch klar, gibts aber irgendeinen logischen Grund warum man sowas in Funktionen benutzen kann aber in Klassen nicht
Ich schätze es liegt daran: Die Größe einer Klasse sollte möglichst Compilezeit-konstant sein, sonst wird die Adressberechung von Variablen rekursiv und damit sehr kompliziert. Die Größe eines Activation Records einer Funktion muss dagegen nicht unbedingt konstant sein, da sie sich nicht rekursiv verschachteln lassen und damit die Adressen lokaler Variablen bei Anwesenheit von variablen Arrays immer noch relativ einfach berechnen lassen.
-
Eine Frage zu dem nützlichem Code von operator void:
Gibt es andere Datenstrukturen der STL, die schneller beim Zugreifen auf ein n-tes Element sind? Denn das ist es was ich möglichst schnell machen muss (Durchhangeln von vorne nach hinten würde auch gehen), das Hinzufügen von Daten zum Beispiel kann ruhig entsprechend langsamer sein.
-
Hm, direkt schneller als ein vector bzw. roher Zeiger/rohes Array (läuft aufs selbe hinaus) ist eigentlich nichts - man kann sonst noch darauf achten, dass die Daten für den Prozessor immer gut zugreifbar liegen. Außerdem könnte ich mir vorstellen, dass ein Zugriff auf vector<int>-Elemente schneller geht als auf die eines vector<char>, weil die an 32bit-Grenzen ausgerichtet werden etc. usw. - aber einen einfachen "schnelleren Container" kann ich mir nicht vorstellen.
-
Hm, direkt schneller als ein vector bzw. roher Zeiger/rohes Array (läuft aufs selbe hinaus)
Läuft absolut nicht aufs selbe hinaus.
Es geht ja nicht nur um den Zúgriff. Auch das Instanzieren braucht seine Zeit.
Die Containerklasse vector ist dabei nicht gerade als optimal anzusehen ...
-
Knallhart zum Thema beigetragen
-
operator void schrieb:
Knallhart zum Thema beigetragen
Musste nunmal sein, wenn hier so'n Müll erzählt wird.
-
@rofl: Du hast sicher recht, jedoch bezog sich (denk ich mal) operator voids Beitrag auf meine Frage, wo ich ausschließlich vom Zugriff sprach.
Tja, wenn der Vector beim Zugriff genauso schnell ist wie ein normales Array (oder fast) dann kann die miese Performance (Prog läuft noch 1/3 so schnell wie vorher mit C) eigentlich nur noch an der Zuweisung eines Koordinaten-Objektes mit 3 Membervariablen und nachfolgenden Zugriffen darauf liegen. Das wird immerhin (zusammen mit dem Vector-Zugriff) ungefähr 3 000 000 mal pro Sekunde ausgeführt...
-
Ist die entsprechende Stelle klein genug, um sie hier kurz zu erklären? Wie Quellcode beim Übersetzen von C nach C++ dreimal langsamer wird interessiert mich doch irgendwie