typedef, array und new
-
Wieso musst Du das denn dynamisch anlegen?
-
Ich nutze die ID als Key in einer map (bzw. ID*). Der value der map ist eine Klasse mit ein paar Daten und auch ID als Member. Wird ein Objekt der Klasse kopiert, ändert sich die Adresse von ID bzw. der Zeiger auf ID wird ungültig.
So in etwa:
class Data { public: const ID* GetID() const {return &id;} private: ID id; } ... map<ID*,Data> m; ... Data d(...); m.insert(d.GetID(),d);
-
ihoernchen schrieb:
Mein Problem: wie erzeuge ich ID dynamisch?
So könntest Du es machen
int main() { ID id1; ID *id2 = malloc(sizeof (ID)); id1[0] = 123; (*id2)[0] = 456; printf ("%d %d %d %d\n", id1[0], (*id2)[0], sizeof(*id2), sizeof(ID)); }
-
ihoernchen schrieb:
...
In Deinem Beispiel entspricht aber schon ID* von Data in der Map nicht mehr dem ID* vom Key.
Also Deinem Beispiel oben folgend...map<ID*,Data>::iterator elemIter = m.find(d.getID()); std::cout << std::boolalpha << (elemIter->GetID() == d.GetID()) << '\n'; //->liefert false!Bist Du sicher, dass Du das willst?
-
C-Fan 2009 schrieb:
So könntest Du es machen
Wenn bitte auch an die Freigabe denken... Und das C-Forum ist nebenan.
-
Tachyon schrieb:
ihoernchen schrieb:
...
In Deinem Beispiel entspricht aber schon ID* von Data in der Map nicht mehr dem ID* vom Key.
Also Deinem Beispiel oben folgend...map<ID*,Data>::iterator elemIter = m.find(d.getID()); std::cout << std::boolalpha << (elemIter->GetID() == d.GetID()) << '\n'; //->liefert false!Bist Du sicher, dass Du das willst?
Ich vergleiche nicht die Zeiger sondern den Inhalt. Die Daten Objekte können beliebig kopiert werden und teilen sich über einen shared pointer die ID. Ich will das kopieren der IDs selbst möglichst vermeiden.
Die Adresse der ID ist egal; die schau ich mir nicht weiter an.Oben fehlt noch die comparsion class (vielleicht fehlt immer noch was, ich bin zu faul das abzugleichen):
struct cmp { bool operator()(const ID* id1,const ID* id2) {return CompareID(id1,id2)<0;} }; map<ID*,Data,cmp> m;
-
ihoernchen schrieb:
Ich will das kopieren der IDs selbst möglichst vermeiden.
Warum? Die IDs zu kopieren ist wahrschenlich nicht so teuer wie der ganze Aufwand mit den shared_ptr und vor allem der Speicherallokierung.
-
Das war eher so ein Bauchgefühl

Das erzeugen und kopieren der Daten Objekte ist unkritisch. Ich halte es für besser die IDs als Zeiger zu speichern. Sonst hätte ich sie doppelt (Key in der map und im Daten Ojekt) und der Zeiger ist trotz des overheads für den reference count günstiger.
-
ihoernchen schrieb:
Das war eher so ein Bauchgefühl

Das erzeugen und kopieren der Daten Objekte ist unkritisch. Ich halte es für besser die IDs als Zeiger zu speichern. Sonst hätte ich sie doppelt (Key in der map und im Daten Ojekt) und der Zeiger ist trotz des overheads für den reference count günstiger.Eine ID sind 16 Byte. Ein Zeiger sind 4 byte, der refcounter nochmal ein paar byte, plus den Speicherverwaltungsaufwand für die Größe des allokierten Bereichs (auch ein paar byte). Zugegeben, es ist ein refcounter und ein Speicherinfo-Block. Aber da du vermutlich jede ID einmal vergeben wirst heißt das vielleicht 4mal die selbe ID, auf die sich der refcounter und die SPeicherverwaltung aufteilen. Sagen wir also pro pointer 2 zusätzliche bytes minimum. Macht also nurnoch einen Unterschied von 10 Bytes pro Pointer.
Das ist lächerlich. Nicht mitgerechnet ist der Zeitaufwand, der bei jeder neuen ID gemacht werden muss um dafür neuen Speicher zu ordern. Den Zeitaufwand und den Speicherverbrauch für die Speicherinfo könnte man noch reduzieren wenn man einen Small-Object-Allocator einsetzt, aber es lohnt einfach nicht.Das war eher so ein Bauchgefühl

Bauchgefühl hat da nichts verloren. Vernünftige Abschätzungen sind das mindeste, im Zweifel ist Wissen das beste, und das erhält man wenn man einen Profiler bemüht und nicht durch Gefühl

-
ihoernchen schrieb:
Das war eher so ein Bauchgefühl

Premature Optimization Is Evil.
Im allgemeinen holst du nichts raus und machst dir das Leben unnötig schwer. Lasst den Kompiler deinen Code optimieren, der kennt ein paar gute Tricks und prüfe erst später über einen Profiler nach, wo es wirklich Probleme gibt.ihoernchen schrieb:
Sonst hätte ich sie doppelt (Key in der map und im Daten Ojekt) ...
Verstehe ich richtig, dass die ID auch im Objekt zum Key der Map ist?
-> http://www.boost.org/doc/libs/1_39_0/libs/multi_index/doc/index.htmltypedef boost::multi_index_container < Data, boost::multi_index::indexed_by < boost::multi_index::ordered_unique < boost::multi_index::const_mem_fun < Data, IdStruct, &Data::get_id > > > > SetContainer;Das ist ein Set, welches die Elemente vom Typ
Datanach den Objekten vom TypIdStructordnet, welche wiederrum vomDataObjekt über die Memberfunktionget_id()geholt werden.
Man kann, im Gegensatz zu einem normalenstd::set, hier auch über einIdStructeinDataObjekt holen gehen.Grüssli

-
pumuckl schrieb:
Nicht mitgerechnet ist der Zeitaufwand, der bei jeder neuen ID gemacht werden muss um dafür neuen Speicher zu ordern. Den Zeitaufwand und den Speicherverbrauch für die Speicherinfo könnte man noch reduzieren wenn man einen Small-Object-Allocator einsetzt, aber es lohnt einfach nicht.
Genau das ist ja der Punkt. Es werden keine IDs erzeugt (zumindest nicht von mir). Das erzeugen ist irrelevant. Aber, es wird sehr oft anhand der IDs gesucht.
Den shared ptr habe ich genommen, weil ich in der map die Adresse der IDs speichere. Würden die ID Objekte mit dem Data Objekt verbunden sein, wären die Adressen nach einem kopieren ungültig.pumuckl schrieb:
Bauchgefühl hat da nichts verloren. Vernünftige Abschätzungen sind das mindeste, im Zweifel ist Wissen das beste, und das erhält man wenn man einen Profiler bemüht und nicht durch Gefühl

Das habe ich versucht. Es gibt keinen Grund für einen Profiler, weil es kein performance Problem gibt.
Dravere schrieb:
Premature Optimization Is Evil.
Im allgemeinen holst du nichts raus und machst dir das Leben unnötig schwer. Lasst den Kompiler deinen Code optimieren, der kennt ein paar gute Tricks und prüfe erst später über einen Profiler nach, wo es wirklich Probleme gibt.Das war keine Optimierung. Zumal so eine Aussage schön klingt, mehr aber auch nicht.
Ich finde die gewählte Lösung nicht kompliziert. Ich habe einen Zeiger auf ein ID Objekt. Nicht mehr. Ich bin gerne offen für Vorschläge zum genannten Problem. Allgemeine Aussagen helfen nicht weiter.Ich kann natürlich die ID als Kopie in die map eintragen. Dann hab ich sie 2 mal. Das gefällt mir nicht.
multi_index_container scheint oversized. Die Sortierung ist egal. Ich habe einen Schlüssel mit dem ich einen Wert finden will. Mehr nicht

-
#include <boost/shared_ptr.hpp> #include <boost/checked_delete.hpp> typedef unsigned char uint8; typedef uint8 ID[16]; int main() { ID id1; ID* id2 = new ID[1]; delete [] id2; boost::shared_ptr<ID> id3(new ID[1], boost::checked_array_deleter<ID>()); }Geht zumindest unter VC8. Comeau Online (aktuelle Version) frisst id2 auch (id3 nicht probiert, weil keine Boost Headers).
Wäre nicht der schönste Workaround, aber dafür wohl der einfachste. Und müsste IMO 100% wasserdicht sein.
-
ihoernchen schrieb:
Genau das ist ja der Punkt. Es werden keine IDs erzeugt (zumindest nicht von mir).
Wenn du die IDs in deinen Data-Objekten drin lässt und sie dort nicht durch smart-pointer ersetzt, dann darfst du als Key auch keine smart-pointer verwenden, die die Kontrolle über Heap-Objekte haben wollen. Dann würden normale Pointer ausreichen.
Generell wirst du aber so oder so einen Comparator schreiben müssen - dann kannst du auch gleich einen schreiben der Dataobjekte nach den IDs vergleicht, diesen als Sortier-Prädikat für ein std::set verwenden und dann mittels lower_bound, upper_bound etc. die richtigen Objekt darin finden.