alternative zu placement new
-
Decimad schrieb:
Ich beginne an der Intelligenz der Leute vom Standard zu zweifeln.
Naja, manchmal frag ich mich auch ein wenig. Obwohl ich nicht glaube, dass es an der Intelligenz der Leute liegt...
Decimad schrieb:
This informs the vector of a planned increase in size, although notice that the parameter n informs of a minimum, so the resulting capacity may be any capacity equal or larger than this.
Eben, dort steht ja extra ein Satz mit "although". Ich kann mir vorstellen, dass man in den meisten Fällen mit
reserve()
nicht gross Speicher verschwendet haben wird, aber man sollte sich nicht darauf verlassen.unskilled schrieb:
gut - auf 25% kommt man, wenn man für nur eine dimension nen vector nutzt und für die andere nen pointer-array?!
Keine Ahnung, was du so kompliziert machst.
Also, du hast einen
std::vector
. Nehmen wir an, dass er sich mit doppelter Kapazität reallokiert, wenn diese nicht mehr ausreicht. Nach der Reallokation wird nur 50% des Speichers verwendet (eigentlich ein bisschen mehr, aber vernachlässigen wir das) - also ist die Hälfte des angeforderten Speichers belegt.Wenn du nun das Ganze in zwei Dimensionen machst, besteht jeder Vector aus einigen Vectoren. Im Worst Case wird von denen wiederum nur 50% benötigt.
Ein zu 50% ausgelasteter Vector, dessen Elemente wiederum nur zu 50% ausgelastet sind, führt zu einer effektiven Nutzung des angeforderten Speichers von 25%.
-
Hat jemand andere verbreitete STL-Implementationen angeschaut? Wie gesagt, Visual C++ 2008's STL alloziert mit reserve auf das Byte genau.
-
ihr redet mit euren Prozenten aneinander vorbei
der eine redet davon, wieviel Prozent des angeforderten Speichers tatsächlich genutzt werden (~25% im worst case), der andere redet davon, wieviel Prozent des benötigten Speichers angefordert werden (~400% im worst case)Decimad schrieb:
Ich beginne an der Intelligenz der Leute vom Standard zu zweifeln. Der einzige Grund, der mir überhaupt nur einfiele wäre derjenige, dass man nur Blöcke mit einer bestimmten Größe größer als sizeof( typ ) allozieren kann.
Dass die Standardler das so ausdrücken, liegt einfach daran, dass sie die Implementatoren nicht zu weit einschränken wollen. Stell dir vor, jemand hat ein Speicherverwaltungstool, in dem tatsächlich nur Blöcke bestimmter Größe angefordert werden können. Oder irgendein OS besteht darauf dass der Speicher entsprechend unterteilt wird. Auf der anderen Seite stünde im Standard "vector alloziert genau so viel Speicher wie angegeben wurde. Aus die Maus mit dem templateparameter Allocator, weil nicht jede Speicherverwaltung es dem vector ermöglicht, exakt den Speicher zu reservieren der angegeben wird. Und aus die Maus mit Portabilität, weil der Standard durch unsinnige Restriktionen verhindern würde, dass vector auf dem BigMemBlock-OS implementiert werden kann.
std::vector<char> vc; vc.reserve(41); std::cout << vc.capacity() << std::endl;
Was da wohl rauskommt? ich würde mal schätzen, da kommt 42, 44 oder 48
raus, je nachdem ob das OS den Speicher in 16 bit, 32 bit oder 64 bit Blöcke unterteilt
-
pumuckl schrieb:
alloziert
Vorher hätte ich sothis_ beinahe geantwortet, aber seine Trollposts sind mir oft einfach zu blöde.
Nur weil er hier spammt, brauchst du dich nicht beeinflussen zu lassen. "Allokieren" ist genauso ein deutsches Wort.
-
stimmt - hatte es wohl unzureichend gelesen und deshalb
was kommt denn bei dir raus?
also bei mir kommt 41 raus...
(MS VC 2008 Prof, Vista 64bit)bei folgendem code
std::vector<char> vc; std::cout << vc.capacity() << std::endl; vc.reserve(22); std::cout << vc.capacity() << std::endl; for (char i(0); i != 41; ++i) { vc.push_back (i); std::cout << vc.capacity() << std::endl; }
kommt bei mir 0 / 22 / 33 / 49 raus (nat. jeweils mehr als einmal ^^)
wobei ich es trotzdem sehr sinnvoll finde doppelt so viel zu reservieren wie benötigt wird... stellt euch so was mal vor:
std::vector <int> r; for (size_t i(0); i != 100; ++i) r.push_back(i);
das würde also zu 100 mal umkopieren führen(was man aber eigtl super mit nem reserve unterbinden könnte - aber soll ja auch fälle geben, wo man nicht weiß, wie viele elemente in dem vector platz brauchen werden) - oder man reserviert immer ein wenig mehr ram (und was ist schon doppelt so viel - wenn man 100 elemente speichert, kann man imho auch für 200 platz in anspruch nehmen - ob es bei verschachtelten vectoren dann net mehr so toll ist, kommt ja auch auf das anwendungsgebiet an)...
davon abgesehen ist pumuckl´s begründung wahrscheinlich die wichtigere/bessere/...bb
-
Na klar, ich find das auch ok, dass der vector beim IMPLIZITEN vergrößern "großzügig" ist. Aber ich finde es NICHT ok, wenn der vector das auch noch macht, wenn ich ihn explizit (reserve) darauf hinweise, dass es genau so groß sein soll (aber es ist okay, dass er dann nicht noch extra schrumpft).
Ich erwarte folgendes:
std::vector<int> v; v.reserve( 10 ); for( int i=0; i<10; ++i ) v.push_back( i ); assert( v.capacity() == 10 );
Alles andere ist mir eigentlich egal.
-
-
Ich fände, eine Art Flag oder globales Makro wäre angebracht, um die Grosszügigkeit seiner Vector-Implementierung einzuschränken. Ähnlich wie das Makro zur Abschaltung der Sicherheitsabfragen.
Damit könnte man z.B. auch
push_back()
begrenzen. Aber naja, da kommt man auch einer eigenen Klasse näher, schlussendlich wirds auf eigenes Coden hinauslaufen...
-
Jopp - ich hab dann aber doch wieder ne Frage:
values = static_cast <ValueType*> (operator new (sizeof(ValueType) * row_count));
kann ich davon ausgehen, dass padding/... hier berücksichtigt wird bzw. wie sollte man das besser lösen?
bb
-
Ich denke mal dass k(aum )ein Implementor der Standardbibliothek sich dazu erdreistet hat bei einem reserve() dem OS unnötig viel Speicher abzutrotzen. Ich würd mich in erster Linie drauf verlassen, dass vector das schon ganz richtig macht und erst wenn es Performanceprobleme gibt und mein Profiler mir sagt dass vector schuld ist überleg ich mir Alternativen. Alles andere ist PMO
Außerdem gibts die gleiche Situation beim int (!): Der Standard schreibt nicht vor wie groß er sein soll. Nur dass er größer als short und char ist. Genauso wie der vector beim reserve also einige Megabyte sinnlosen Speicher reservieren darf, ists dem Compilerhersteller auch nicht verboten, einen int auf 200MB Größe festzulegen. Trotzdem kommt keiner auf die Idee da was eigenes zu implementieren/edit:
unskilled schrieb:
bzw. wie sollte man das besser lösen?
mit operator new[]
-
pumuckl schrieb:
/edit:
unskilled schrieb:
bzw. wie sollte man das besser lösen?
mit operator new[]
Oo
Vll hätte ich den Zusammenhang mit posten sollen (das war das new statt malloc)values = static_cast <ValueType*> (operator new (sizeof(ValueType) * row_count)); SizeType index = SizeType(); try { for (; index != row_count; ++index) { ValueType *tmp = value[index]; tmp = new (tmp) ValueType (fill_with); } } catch (...) { Destruct(index); throw; }
Oder gibt es einen operator new[], der uninitialisierten Speicher hinterlässt? ^^
bb
edit:
analog dazu das löschen:for (ValueType *iter = values, *end = values+length; iter != end; ++iter) { if(iter) iter->~ValueType(); } operator delete (values); values = nullptr;
-
unskilled schrieb:
Oder gibt es einen operator new[], der uninitialisierten Speicher hinterlässt? ^^
Ja, genau analog zu
operator new
.
-
und hier kann ich mir dann sicher sein, dass er alignment und padding beachtet:
values = static_cast <ValueType*> (operator new [sizeof(ValueType) * row_count]); //operator delete[] (values);
?
Falls nicht, sehe ich keinen Unterschied in der Lösung und der davor (abgesehen vom optischen ^^). Falls ich jz iwas falsch verstanden habe, mach ma pls nen kurzes Bsp
bb
-
Vielleicht nochmals zusammenfassend:
T* ptr = operator new(sizeof(T)); T* ptr = operator new[](5*sizeof(T));
Hiermit wird Speicher allokiert und nicht initialisiert.
new (ptr) T;
Das Placement New initialisiert den Speicher
ptr
, indem eine Instanz an dieser Speicherstelle konstruiert wird. Es können auch Konstruktorargumente fürT
übergeben werden.ptr->~T();
Der explizite Destruktoraufruf ist erforderlich, wenn Zerstörung und Deallokation separat behandelt werden.
operator delete(ptr); operator delete[](ptr);
Der
operator delete
bzw.operator delete[]
gibt den Speicher an der Speicherstelleptr
frei. Hier muss man darauf achten, dass die korrekte Version aufgerufen wird.
-
unskilled schrieb:
und hier kann ich mir dann sicher sein, dass er alignment und padding beachtet:
values = static_cast <ValueType*> (operator new [sizeof(ValueType) * row_count]);
So kannst du
operator new[]
gar nicht aufrufen (siehe mein letzter Post). Eigentlich brauchst du nuroperator new
.Also so:
values = static_cast<ValueType*>(operator new(sizeof(ValueType) * row_count);
Hier sollte kein Problem wegen Alignment entstehen.
Aber du kannst auch einfach den
std::allocator
verwenden.
-
@unskilled,
sizeof
berücksichtig padding und co. Kannst es auch selber testen:struct Foo { int a; char b; }; int main() { std::cout << sizeof(Foo) << std::endl; return 0; }
Kommt bei mir ganz klar 8 dabei raus.
<?xml version="1.0" ?> <off-topic operation="klugscheiss"> <talk-to name="Nexus"> <definition-of value="allokieren">anreden, trösten</definitin-of> <definition-of value="allozieren">zuweisen, bereitstellen</definition-of> <reference type="url">http://faql.de/fremdwort.html#allocate</reference> <commenct>sothis_ hat es zwar nicht nett gesagt, aber recht hat er.</comment> </talk-to> </off-topic>
Und ich will jetzt kein "Nerd" oder ähnliches hören.
Grüssli
-
Danke ^^
Die Zeile hätte schon gereicht - den Rest hatte ich auch so verstanden, nur das konnte ich mir nicht so richtig denken ^^
T* ptr = operator new[](5*sizeof(T));
Aber du kannst auch einfach den std::allocator verwenden.
Hmm... xD Die Idee hätte glatt von mir stammen können... Verdammt ^^ Naja - man lernt ja bei so was wenigstens immer dazu ^^
Kommt bei mir ganz klar 8 dabei raus.
Stimmt - bei mir auch... So gar im x64-Mode oO
bb
-
Dravere schrieb:
Und ich will jetzt kein "Nerd" oder ähnliches hören.
Nene, aber ist gut, dass du meine Gedanken kennst. :p
Aber die ersten beiden Quellen bei Google sagen da etwas Anderes (im Buch hab ich das Wort nicht finden können):
www.duden.de schrieb:
al|lo|kie|ren <zu mlat. allocare>: für einen bestimmten Zweck bereitstellen (bes. Datenv.)
de.wiktionary.org schrieb:
allokieren (Deutsch)
Bedeutungen:
[1] Informatik: (Arbeitsspeicher) belegenSynonyme:
[1] anfordern, belegen
-
Hast du nicht auch die Diskussion auf "de.wiktionary.org" gelesen?
http://de.wiktionary.org/wiki/Diskussion:allokierenIn meinem Duden Zuhause (23. Auflage) befindet sich kein allokieren. Wenn ich im Duden im Web suche, finde ich nur das, was ich schon gesagt habe. Interessanterweise komme ich aber über Goolge auf die Website, welche du per Copy&Paste präsentierst, aber das geht nur über Google
Jedenfalls nach ursprünglicher Bedeutung, macht allozieren deutlich mehr Sinn. Mir ist allerdings nicht klar, ob es so ist, wie in der Dikussion auf Wikitionary erwähnt wird, dass die Informatiker einfach zu dumm waren und das allokieren nun auch in dieser Art in die Sprache aufgenommen wurde.
Naja, wie auch immer, mit allozieren ist man ganz sicher, auf der richtigen Seite
Grüssli
-
gottseidank sind wir keine Compiler die bei nem Tippfehler oder falsch verwendeten Wort einfach aussteigen. Hauptsache ist doch man kann ohne Schwierigkeiten den Text verstehen, und dass keiner hier den armen Speicher trösten will sollte ja bekannt sein
Vllt. kann man sich drauf einigen, neudeutsch "allocieren" zu schreiben - dann kann sich jeder aussuchen wie er das c gern aussprechen möchte.
Oder man verlegt sich aufs englische, so dass die Leute genug damit zu tun haben, ihren eigenen Satzbau zurechtzufrickeln und Kleinigkeiten geduldet werden