Wie?: Klassenvariable, die für jedes Objekt global ist.
-
eine Frage bitte schrieb:
Ich habs zwar auch ohne vector hinbekommen, nur das Blöde ist, dass beim Anlegen des Zwischenspeichers new den Konstoruktor der Klasse aufruft. - Ideen?
operator new[sizeof(asd)*length]
und dann mit placement new den ctor aufrufen#btw:
void create(Medium* medium){ if(medium==NULL){ medium = new Medium[1]; /*...*/ } }das funzt? Oo
Ich glaube eher nicht... ^^
der Pointer wird nämlich kopiert -> du veränderst nur die kopie...
richtig wäre eine referenz auf einen zeiger - dann kannst du dem auch (wirkungsvoll) was zuweisen...
btw: new Medium**[1]** ist doch hässlich... vor kurzem war hier scho ma jmd, der ständig ne 1 als dimension gewählt hat - ist das jetzt in, sowas zu machen?new Mediumsieht wohl zu übersichtlich aus?
bb
PS: (offtopic)
wieso kann man noch immer nicht fett courir schreiben? -.- also so: [c]bla[/c]
-
unskilled schrieb:
operator new[sizeof(asd)*length]Du meinst wohl
operator new[] (sizeof(asd) * length);Das gibt allerdings nur einen
void*zurück und muss noch in den Zieltypen gecastet werden. Statt Placement New kann man auch die C++-Funktionenstd::unitialized_copy(),std::unitialized_fill()oderstd::unitialized_fill_n()verwenden.Allerdings kann man die []-Klammern eigentlich auch weglassen (und gleich
operator neweinsetzen), wenn man Allokation und Konstruktion trennt. Bei der Freigabe sollte man vorsichtig sein, da man zuerst für jedes Element den Destruktor aufrufen muss. Ich hatte das selber schon benötigt und eine entsprechende Funktion geschrieben:// Ruft für alle Elemente in der Zeiger-Range [first, last[ den Destruktor auf. template <typename T> void destroy_range(T* first, T* last) { for (; first != last; ++first) { first->~T(); } }Wieso gibt es diese Funktion eigentlich in der Standardbibliothek nicht? Die Gegenstücke bei der Konstruktion sind ja auch vorhanden...
-
Nexus schrieb:
unskilled schrieb:
operator new[sizeof(asd)*length]Du meinst wohl
operator new[] (sizeof(asd) * length);japp - in letzter zeit hab ichs iwie nich so mit dem nachdenken

Nexus schrieb:
Das gibt allerdings nur einen
void*zurück und muss noch in den Zieltypen gecastet werden.Jopp - wo ist das Problem?
Nexus schrieb:
Statt Placement New kann man auch die C++-Funktionen
std::unitialized_copy(),std::unitialized_fill()oderstd::unitialized_fill_n()verwenden.hatte ich ja noch nie gehört - ich seh jz auch nicht wirklich nen vorteil darin - überseh ich was? ^^
Nexus schrieb:
// Ruft für alle Elemente in der Zeiger-Range [first, last[ den Destruktor auf. template <typename T> void destroy_range(T* first, T* last) { for (; first != last; ++first) { first->~T(); } }Wieso gibt es diese Funktion eigentlich in der Standardbibliothek nicht?
Gute Frage - ich habs bis jz aber auch immer selbst geschrieben ^^
bb
-
unskilled schrieb:
Jopp - wo ist das Problem?
Wo sagte ich etwas von Problem? Ich wollte es nur erwähnen, da das vielleicht hilfreich sein könnte.

Nexus schrieb:
hatte ich ja noch nie gehört - ich seh jz auch nicht wirklich nen vorteil darin - überseh ich was? ^^
Keinen Vorteil? Na gut, wenn du dir immer alles selbst schreiben willst.

Nehmen wir an, du hast einen
vector-ähnlichen Container.template <typename T> class dynamic_array { public: // separater Ctor statt Defaultparameter wäre besser, hier aber irrelevant... dynamic_array(size_t num_elements, const T& value = T()); dynamic_array(const dynamic_array& origin); private: size_t m_size; // mal ohne capacity T* m_array; }; // Konstruktor mit Grösse und Default-Element als Parameter template <typename T> dynamic_array<T>::dynamic_array(size_t num_elements, const T& value) : m_size(num_elements) , m_array(static_cast<T*>(operator new(sizeof(T) * m_size))) { std::uninitialized_fill_n(m_array, m_size, value); } // Kopierkonstruktor template <typename T> dynamic_array<T>::dynamic_array(const dynamic_array<T>& origin) : m_size(origin.m_size) , m_array(static_cast<T*>(operator new(sizeof(T) * m_size))) { std::uninitialized_copy(origin.m_array, origin.m_array + m_size, m_array); }Nur so als Beispiel. Man könnte die Funktionalität natürlich noch mehr kapseln, mindestens als freie Funktionen oder sogar als Allokatoren. Aber grundsätzlich sind die
std::uninitialized_...-Funktionen relativ nützlich. Nur reichen sie nicht ganz aus. Ich habe bei mir einen Header, bei dem mehr oder weniger sinnvolle Raw-Memory-Funktionen vorhanden sind (darunter oben genanntesdestroy_range()).
-
Also irgendwas mach ich eindeutig falsch.
class Medium{ protected: ... public: ... void* operator new[] (std::size_t size); };Aufruf:
Medium* create(Medium* medium){ // medium stets != NULL void *p = new Medium[medium->getBestand()+1]; }Und das quitiert mir VS08 mit:
Error 1 error LNK2019: unresolved external symbol "public: static void * __cdecl Medium::operator new[](unsigned int)" (??_UMedium@@SAPAXI@Z) referenced in function "class Medium * __cdecl create(class Medium *)" (?create@@YAPAVMedium@@PAV1@@Z) functions.obj
Error 2 fatal error LNK1120: 1 unresolved externals C:\Dokumente und Einstellungen\IM\Eigene Dateien\Visual Studio 2008\Projects\Medienbib2\Debug\Medienbib2.exe 1
-
Wenn du den
operator new[]deklarierst, musst du auch dafür sorgen, eine eigene Implementierung (Funktionsdefinition) zur Verfügung zu stellen. Meistens besteht aber kein Grund, die Speicheranforderungs-Operatoren zu überladen. Also versuch mal, die Deklaration wegzulassen.
-
Ups.
void* operator new[](std::size_t size){ return (void*) (size*sizeof(Medium)); }Was er mir nun liefer ist eine excess violation.
Bzw., eigentlich ist es wirklich unnötig und die Aufgabenstellung schreit ja gerade zu nach einer verketteten Liste aber ich hätts tortzdem gern hinbekommen.
-
eine Frage bitte schrieb:
excess violation.
Hehe...

void* operator new[](std::size_t size){ return (void*) (size*sizeof(Medium)); }Weisst du, was du hier machst? Du multiplizierst
sizemitsizeof(Medium). Weil du einen überaus gefährlichen und bösen C-Cast anwendest, merkst du nicht, was du castest. Nämlich einen Integer zu einem Zeiger. Deinoperator new[]tut also so, als wäre das Ergebnis der Multiplikation eine Adresse. Und als wäre an dieser Adresse ein schöner, neu angelegter Speicherbereich für dich.Ich denke, der Rest ist klar.

-
Nexus schrieb:
Weil du einen überaus gefährlichen und bösen C-Cast anwendest, merkst du nicht, was du castest. Nämlich einen Integer zu einem Zeiger.

-
Na wenn ich schon dabei bin, C-Funktionen zu benutzen, kann ich den Speicher wohl auch gleich mit malloc allokieren...
Oder bietet mir C++ bessere Alternativen?
-
eine Frage bitte schrieb:
Na wenn ich schon dabei bin, C-Funktionen zu benutzen, kann ich den Speicher wohl auch gleich mit malloc allokieren...
Oder bietet mir C++ bessere Alternativen?ja.
stattBla* p=malloc(15*sizeof(Bla));sollte man
Bla* p=new Bla[15];schreiben.
die version mit new ruft zusätzlich den konstruktor von Bla für jedes array-element auf. also nix wenn es simple typen sind, und dann ist new auch genausoschnell. aber wenn der konstruktor von Bla code ausführen muß, macht new[] das austomatisch.
deswegen sollte man in c++ grundsätzlich new benutzen, damit man nicht nachdenken muß, ob der typ gerade einer war, der keinen konstruktor hat oder einer, der soch mal einen hat.zum anlegen rohen speichers gibt es operator new(size_t) versus malloc(size_t), die genau gleich sind. naja, fast. operator new ist gerne mal auf kleine objekte optimiert.
-
eine Frage bitte schrieb:
Na wenn ich schon dabei bin, C-Funktionen zu benutzen, kann ich den Speicher wohl auch gleich mit malloc allokieren...
Oder bietet mir C++ bessere Alternativen?Wieso willst du unbedingt
operator new[]selber implementieren? Du kannst doch den vorgefertigten nutzen. Es ist unwahrscheinlich, dass du für den Alltag etwas anderes brauchst. Also entferne endlich dessen Deklaration in deiner Klasse.Und ja, C++ bietet bessere Möglichkeiten. Sieh dir bei Gelegenheit mal STL-Container an.
-
Ja, aber den Aufruf des Konstruktors wollte ich doch unbedingt vermeiden, weil ich vorhatte, mein Array von Medien-Objekten dynamisch zu verwalten. Und dazu musste ich dann neuen Speicher anlegen und es wäre wirklich nicht so toll, wenn dabei stets der Konstruktor aufpoppt.
-
Nun ja, ist auch egal. Ich komme im Moment damit, new zu überladen, sowieso auf keinen grünen Zweig mehr.
Mal was anderes:
class Medium{ private: static int bestand; public: void incBestand(); int getBestand(); }; class Book : public Medium{ private: static int bestand; public: }; class Video : public Medium{ private: static int bestand; public: };Wie kommt es, dass void incBestand() und int getBestand() in den Klassen Book und Video immerzu auf die static-Variable "bestand" aus der Klasse Medium zugreiffen, obwohl die Variable private ist, damit nicht vererbt und sowieso redefiniert wird? Und vor allem: Warum geht es überhaupt? Dachte, auf statische Klassenvariablen könne man nur mit statischen Methoden zugreiffen.
Definiere ich die Methoden in jeder Klasse jeweils als static, funktioniert alles, wie es soll.
-
eine Frage bitte schrieb:
Hallo!
Ich habe da ein kleines Programm: Gegeben ist eine Basisklasse Medium.
Von Medium werden zwei Klassen, Video und Buch abgeleitet.
Die Klassen (Video und Buch) werden dann zur Programmlaufzeit instanziert und in einem Array gespeichert.
Nun möchte ich folgendes machen: Die Klassen Video und Buch sollen eine Klassenvariable "Bestand" beinhalten, die, wie der Name ja sagt, den aktuellen Bestand an Videos und Büchern speichert. "Bestand" wird also genau dann inkrementiert, wenn ein Objekt von der jeweiligen Klasse angelegt wird.
Der Punkt ist: Wird die Variable "Bestand" inkrementiert, so soll sie in allen Objekten "Buch" oder "Video" gleichzeitig aktualisiert werden, ohne dass ich explizit jedes Objekt aufrufen und dort die Variable verändern muss.Geht das und wenn ja, wie?
Gruß
Bestand ist keine Eigenschaft der Bücher oder Videos, sondern des Dings (Laden/Bücherei) in dem sie sind. Vergiss das mit dem new überladen, mach dir eine Klasse die die Medien hält und beim hinzufügen oder entfernen den Bestand aktualisiert.
-
Ach, und wenn du dir sicher bist, dass es immer nur genau eine Bücherei gibt, dann kannst du die als Google: Singleton machen.
-
eine Frage bitte schrieb:
Wie kommt es, dass void incBestand() und int getBestand() in den Klassen Book und Video immerzu auf die static-Variable "bestand" aus der Klasse Medium zugreiffen, obwohl die Variable private ist, damit nicht vererbt und sowieso redefiniert wird?
private Member werden vererbt, die erbende Klasse hat nur keinen direkten Zugriff darauf, aber vererbte Funktionen dürfen trotzdem normal darauf zugreifen, wäre das nicht so würden ja einzellne Funktionen uU nichtmehr funktionieren. Deine 2 Funktionen greifen auf die Variable zu die zu ihrer Klasse gehört, da sie zu Medium gehören greifen sie auch auf die Variable aus Medium zu.
Ich weiß hier leider nicht genau ob man die static wirklich überall einzelln haben muß oder ob eine statische Bestand Variable in Medium nicht reichen würde, weil ich nicht weiß ob sie danach 3x oder trotdzem nur 1x existieren würde.
eine Frage bitte schrieb:
Und vor allem: Warum geht es überhaupt? Dachte, auf statische Klassenvariablen könne man nur mit statischen Methoden zugreiffen.
Du denkst da leider falsch. Nicht statische Funktionen dürfen auf statische Member und Funktionen zugreifen, nur umgedreht geht es nicht.
eine Frage bitte schrieb:
Definiere ich die Methoden in jeder Klasse jeweils als static, funktioniert alles, wie es soll.
Siehe erster Quote.
-
eine Frage bitte schrieb:
Ja, aber den Aufruf des Konstruktors wollte ich doch unbedingt vermeiden, weil ich vorhatte, mein Array von Medien-Objekten dynamisch zu verwalten. Und dazu musste ich dann neuen Speicher anlegen und es wäre wirklich nicht so toll, wenn dabei stets der Konstruktor aufpoppt.
Den Aufruf des Konstruktors vermeidest du indem du einfach
operator new[]selber aufrufst. Schnellerklärung zum Thema: C++ unterscheidet zwischen der Funktionoperator new[]und dem Operatornew. Das, was wir normalerweise im Quellcode schreiben, ist der Operatornew. Der Compiler macht daraus einen Aufruf desoperator new[], gefolgt von entsprechend vielen Konstruktoraufrufen für die ganzen Elemente des Arrays. Ähnliches gilt für den Operatordelete: Hier wird erst der Destruktor aufgerufen, danach dannoperator delete, der nurnoch den Speicher freigibt.
Dein Versuch,operator new[]zu überladen wäre also wirkungslos, die konstruktoren würden immernoch aufgerufen wenn du den Aufruf nicht änderst.Unskilled hatte eigentlich schon den richtigen Hinweis geliefert:
X* blankerSpeicher = operator new[](n*sizeof(X)); //Speicher für n Xe for (int i = 0; i < n; ++i) new (blankerSpeicher + i) X(); //placement new //freigeben: //delete[] blankerSpeicher; //ruft alle Destruktoren auf und dann operator delete[] for (int i = n-1; i >= 0; --i) blankerSpeicher[i].~X(); //manueller Dtoraufruf operator delete[] (blankerSpeicher);Der Fehler bei deinem überladenen
operator newwar übrigens, dass du ihn nicht static deklariert hast. Wenn man sichs genau überlegt kann er garnicht anders als static sein, schließlich gibts kein Objekt, das ihn aufruft um Speicher für ein anderes Objekt zu beschaffen.