Ahhhh, die Erinnerung setzt ein...
pumuckl schrieb:
Wenn ich das richtig sehe kann es aber vorkommen, dass ein objekt, das mit "irgendeinem" Allokator allokiert wurde, mit "irgendeinem" anderen deallokiert wird. In dem Beispiel hätte der zweite Allokator ein Objekt zu deallokieren das nicht in seinem pool ist.
Ich glaube das ist eine "Grauzone" im Standard bzw. dessen Auslegung, oder zumindest was existierende Implementierungen angeht.
Allokatoren müssen nämlich soweit ich weiss den operator == implementieren, und zurückgeben, ob sie "kompatibel" sind. Also in meinem vorgeschlagenen Pool-Fall, ob sie den gleichen Pool verwenden.
Beispiel aus der MSVC 9 Standard-Library, Implementierung von std::vector<T>:
P.J. Plauger schrieb:
void swap(_Myt& _Right)
{ // exchange contents with _Right
if (this == &_Right)
; // same object, do nothing
else if (this->_Alval == _Right._Alval)
{ // same allocator, swap control information
#if _HAS_ITERATOR_DEBUGGING
this->_Swap_all(_Right);
#endif /* _HAS_ITERATOR_DEBUGGING */
this->_Swap_aux(_Right);
_STD swap(_Myfirst, _Right._Myfirst);
_STD swap(_Mylast, _Right._Mylast);
_STD swap(_Myend, _Right._Myend);
}
else
{ // different allocator, do multiple assigns
this->_Swap_aux(_Right);
_Myt _Ts = *this;
*this = _Right;
_Right = _Ts;
}
}
Der "different allocator" Zweig verletzt hierbei auch die O(1) Garantie. Geht IMO auch nicht anders, da Allokatoren AFAIK nicht "no-throw assignable", und nicht "no-throw swappable" sein müssen. Dadurch kann man die Allokatoren nicht einfach tauschen, da es schief gehen könnte. Und nach dem "schief gehen" könnte ein versuchtes "Undo" ebenfalls schief gehen, und dann wäre man komplett angeschmiert.
(Dass der *Allokator-Typ* gleicht ist, ist natürlich schon allein dadurch garantiert, dass Container mit unterchiedlichen Allokator-Typen, schon komplett unterschiedliche (und unverwandte) Klassen sind, also vec.swap(other) gar nie aufgerufen werden kann, wenn other einen unterschiedlichen Allokator-Typ verwendet)
In anderen swap Funktionen, sowie den "splice", "merge", ... Funktion von "std::list" findet man ähnliche Konstrukte.
Aber mal ganz davon abgesehen dass es vermutlich keine bessere Lösung gibt, als die Elemente in swap() in diesem "Spezialfall" zu kopieren... führt mich das ganze zur Annahme, dass die Standard Library sehrwohl garantiert, dass Objekte mit "dem selben" (=einem kompatiblen) Allokator freigegeben werden, über den sie auch angefordert wurden.
----
Dravere schrieb:
Dann müsste man also in jedem Speicherblock zum Beispiel sizeof(void*) zusätzliche Bytes speichern, welche dann einen Zeiger zum korrekten Pool beinhalten?
Das wäre vermutlich ein gangbarer Weg.
Dravere schrieb:
Also auf das, was im Allokator gespeichert ist, darf man überhaupt nicht gehen?
Wenn du maximale Portierbarkeit/Kompatibilität mit vielen Implementierungen haben willst, dann sicher nicht. Sonst u.U. schon. Wobei ich mich mit dieser Einschätzung durchaus irren kann.