void* vs Templates (Split aus "Prozentuale Verteilung der Datentypen")
-
§5.3.3 / 1 schrieb:
sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1
Aber meines Wissens muss 1 byte nicht 8 bit gross sein ... oder? Aber dann gibts ja noch
uint8_t/int8_t...
-
otze schrieb:
Sone schrieb:
a void able schrieb:
operator new könnte genauso gut char* zurückgeben, weil er ein Byte-Array allokiert.
In einem anderen Thread habe ich letztens erst gezeigt, dass
charnicht einen Byte groß sein muss.war das nicht ie Definition von char? Link?
Eric Cartman schrieb:
§5.3.3 / 1 schrieb:
sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1
Aber meines Wissens muss 1 byte nicht 8 bit gross sein ... oder? Aber dann gibts ja noch
uint8_t/int8_t...Ziehe es zurück, da ging es tatsächlich um die Bitzahl, ein char hat also mindestens 8 Bit, dachte, die Bitzahl des Bytes wäre vom Standard definiert... (Link)
Ja,char*könnte tatsächlich von denoperator new/deletebenutzt werden...
-
Sone schrieb:
Ja,
char*könnte tatsächlich von denoperator new/deletebenutzt werden...Also bist du auch der Meinung, dass void* nicht nötig ist?
Ich ziehe sogar meine Aussage zurück, dass void* für die Definition reinterpret_cast gebraucht wird. Das wird nur benötigt, um Blödsinn mit void* und static-casts zu vermeiden.
void* kann immer durch reinterpret_cast und char* ersetzt werden und ich würde meinen, das ist immer besser.
-
a void able schrieb:
void* kann immer durch reinterpret_cast und char* ersetzt werden und ich würde meinen, das ist immer besser.
Hast du dafür auch irgendeine rationale Begründung?
Imo sind void* und char* doch sehr verschiedener Natur. Ein char* flüstert einem z.B. ständig ins Ohr: "Mach Zeigerarithmetik mit mir", ein void* schweigt...
-
a void able schrieb:
Sone schrieb:
Ja,
char*könnte tatsächlich von denoperator new/deletebenutzt werden...Also bist du auch der Meinung, dass void* nicht nötig ist?
Ich bin unentschieden.
-
dot schrieb:
Hast du dafür auch irgendeine rationale Begründung?
char* sagt dir, "ich bin ein Zeiger auf Rohspeicher" und hat irgendeine Länge.
void* schweigt, egal wie viel du über ihn herausfinden willst. Aber genau das muss irgendwann getan werden, sonst nützt er einem nichts. Entweder ist void* ein Zeiger auf einen Typ, dann sollen Templates benutzt werden, oder void* ist ein Zeiger auf Rohspeicher (Beispiel new/delete), dann soll char* benutzt werden.
-
a void able schrieb:
void* schweigt, egal wie viel du über ihn herausfinden willst.
Und wenn ich genau das will? Wieso genau wäre ein char* z.B. im Kontext mit Type Erasure deiner Meinung nach besser als void*?
Dass operator new void* returned ist wohl historisch bedingt. Dass char* dort sinnvoller wäre, seh ich auch so. Ich würde sogar einen Schritt weiter gehen und meinen, dass das ganze Konzept von new eigentlich flawed ist und die Allokation von Speicher rein Aufgabe einer Library sein sollte. Die Sprache sollte lediglich die Möglichkeit bieten, Objekte in einem gegebenen Speicherbereich zu konstruieren...
-
Zum Template-Bloat mit void* ist mir ein Beispiel eingefallen. Man hat einen Baum und verschiedene Algorithmen darauf (Liste in DFS-Reihenfolge generieren, Liste in BFS-Reihenfolge generieren). Dann könnten die Daten als void* gespeichert werden, weil sie nicht interessieren.
Aber dann existiert eine noch opakere Lösung:
template <typename Data> struct node { node *left, *right; /* some internal datas */ Data d; }; typedef node<std::aligned_storage<sizeof(char*), std::alignment_of<char*>::value> generic_node
-
Das typedef habe ich etwas verhauen:
typedef node<std::aligned_storage<sizeof(char*), std::alignment_of<char*>::value>::type> generic_nodeAber ich denke, besser wäre ein zentraler generic_pointer:
// das gleiche wie ein void*, nur dass es nicht einfach zu etwas anderem gecastet werden kann. typedef std::aligned_storage<sizeof(char*), std::alignment_of<char*>::value>::type generic_pointer; // unserer generischer knoten: typedef node<generic_pointer> generic_node; // node lässt sich ganz einfach auch typsicher machen.
-
dot schrieb:
a void able schrieb:
void* schweigt, egal wie viel du über ihn herausfinden willst.
Und wenn ich genau das will? Wieso genau wäre ein char* z.B. im Kontext mit Type Erasure deiner Meinung nach besser als void*?
Hast du denn ein Beispiel wo man void* oder char* braucht?
Ich denke nämlich, dass es nicht notwendig ist.
-
Der Tobi schrieb:
void-Pointer kann man sehr wohl in C++ brauchen...
Zeig mir ein sinnvolles Beispiel für void* (OHNE eine Bibliotheksfunktion zu benutzen, die das fordert), wo man nicht genauso gut mit Templates arbeiten kann.
Aehm was ist denn das fuer ein Quatsch? Was wenn ich Bibliotheken in C++ schreibe, die in C verwendet werden? Fuer die ganze Interoperabilitaet, abstrakte Datentypen, ... ist void* noetig.
-
Die Begruendung, man koennte doch statt void* ueberall char* verwenden, ist hirnrissig. Letztendlich ist alles ein haufen Bytes, warum also ueberhaupt Typen...
-
Aber meines Wissens muss 1 byte nicht 8 bit gross sein ... oder? Aber dann gibts ja noch uint8_t / int8_t ...
Welchen Sinn macht ein Byte, welches nicht exakt 8 Bit groß ist ???

Hast du denn ein Beispiel wo man void* oder char* braucht?
Ich denke nämlich, dass es nicht notwendig ist.
Ich habe mal einen generischen Container für mehrere Typen geschrieben. Dabei hatte ich den Programmablauf mit Hilfe einer XML Datei gesteuert. Also etwas in der Form:
// Kein Anspruch auf Vollständigkeit! class Node // Klasse zur Speicherung von verschiedenen Datentypen { private: void* Data; std::string Type; public: void Set(const XMLElementA& V) { this->Data = new XMLElementA(V); this->Type = "XMLElementA"; } void Set(const XMLElementB& V) { this->Data = new XMLElementB(V); this->Type = "XMLElementB"; } void Set(const XMLElementC& V) { this->Data = new XMLElementC(V); this->Type = "XMLElementC"; } // ... }; // ... std::list<Node> XMLFileContent;Gibt es da eine andere, elegantere Möglichkeit ?
-
Kellerautomat schrieb:
Die Begruendung, man koennte doch statt void* ueberall char* verwenden, ist hirnrissig. Letztendlich ist alles ein haufen Bytes, warum also ueberhaupt Typen...
Das war nie mein Argument. Ich habe gesagt, dass man
void*fast immer durch Templates ersetzen kann (und das dann besserer Code ist).
In den wenigen Fällen wo das nicht geht, will man meistens einenchar*(Beispiel operator new/delete) oder, wenn es um Template-Bloat geht, einenstd::aligned_storage<char*>.@Bitte ein Bit: Etwas mehr Kontext wäre nicht schlecht. Bei dir sieht es aus, als wären entweder die verschiedenen Klassen unnötig (einfach zwei strings speichern) oder du brauchst eine gemeinsame Basisklasse.
-
Bitte ein Bit schrieb:
Gibt es da eine andere, elegantere Möglichkeit ?
Wenn XMLElementA und XElementB etc. von einer gemeinsamen Basisklasse erben, dann hast du Polymorpgie als Ergebnis.
Aktuell musst du über Type gehen um das korrekte Element lesen zu können. Wenn du es aber über Polymorphie machst, hast du viele Vorteile - zB dass du eine get-Template Funktion schreiben kannst die Typsicher ist.
-
a void able schrieb:
std::aligned_storage<char*>Ich fall jedesmal drauf rein. Ich meinte das, was oben als
generic_pointerdefiniert habe.
-
Bitte ein Bit schrieb:
Aber meines Wissens muss 1 byte nicht 8 bit gross sein ... oder? Aber dann gibts ja noch uint8_t / int8_t ...
Welchen Sinn macht ein Byte, welches nicht exakt 8 Bit groß ist ???

....
Auf Plattformen die keinen Bytezugriff beherrschen. (Es gibt durchaus DSPs die nur 32bit Zugriffe erlauben...)
Greets
Tobi
-
Auf Plattformen die keinen Bytezugriff beherrschen. (Es gibt durchaus DSPs die nur 32bit Zugriffe erlauben...)
Boing, und wieder was gelernt. In der Wiki heißt es sogar dass ein Byte auch weniger Bits haben kann.
Wenn XMLElementA und XElementB etc. von einer gemeinsamen Basisklasse erben, dann hast du Polymorpgie als Ergebnis.
Hmm, könnte auch so klappen. Man könnte dazu in der Basisklasse nur die Typinfo speichern und alle anderen XML Element davon ableiten. Dafür würde die Basisklasse vermutlich aber einen virtuellen Copy Konstruktor als auch virtuellen Zuweisungsoperator benötigen.
-
Bitte ein Bit schrieb:
Dafür würde die Basisklasse vermutlich aber einen virtuellen Copy Konstruktor als auch virtuellen Zuweisungsoperator benötigen.
Nein.
Maximal eine clone() Methode, falls denn unbedingt notwendig.