...
-
class list_base : protected std::allocator_traits<Allocator>::template rebind_alloc<list_node<T>>Wow, das ist das erste Mal, wo ich protected Vererbung sehe und es sogar Sinn macht!
-
template <typename Allocator, typename... Args> typename Allocator::pointer allocator_new(Allocator& allocator, Args&&... args) { auto p = std::allocator_traits<Allocator>::allocate( allocator, 1 ); try { std::allocator_traits<Allocator>::construct( allocator, p , std::forward<Args>( args )... ); } catch (...) { std::allocator_traits<Allocator>::destroy( allocator, p ); // Sollte da nicht deallocate stehen? throw; } return p; }Kellerautomat schrieb:
Die typedefe ich dann einfach mittels:
typedef iterator_impl<false> iterator; typedef iterator_impl<true> const_iterator;So hatte ich es auch am Anfang gedacht.
-
haifaik schrieb:
Sone schrieb:
Es geht mir nicht darum, ob er Böse" ist, sondern darum, dass ich das Problem lieber an der Wurzel packe.
mStartundmEndgehören nicht zur Konstanz der Instanz dazu - wenn die Instanz alsconstqualifiziert ist, dann betrifft dass alle ihre **Listenelemente, aber nicht die HilfsknotenmStart undmEnd**.Die Wurzel des Problems ist die Funktion erase. Die ist unlogisch.
Genau! Das ist aber in der C++11-std::list so, und ich will schließlich standardkonformität wahren.
Ganz unlogisch ist es nebenbei nicht, da nur die List in der gelöscht werden soll non-
constsein sollte. Der Iterator selbst kann jaconstsein.
-
erase() ist ganz und gar nicht unlogisch. Der Iterator dient als Positionsangabe, warum sollte ich dafuer einen non-const iterator brauchen? DAS waere unlogisch.
-
haifaik schrieb:
Unlogisch heisst hier "nicht mit dem Typsystem ausdruckbar". Deshalb ist ein const_cast angebracht.
Oder wie wollt ihr das mit dem Typsystem ausdrücken ohne Hacks wie prev->next?
-
haifaik schrieb:
haifaik schrieb:
Unlogisch heisst hier "nicht mit dem Typsystem ausdruckbar". Deshalb ist ein const_cast angebracht.
Oder wie wollt ihr das mit dem Typsystem ausdrücken ohne Hacks wie prev->next?
Wo sich der Standard hier Gedanken gemacht hat war das Interface, nicht die Implementierung.
-
Du kannst es auch ohne const_cast implementieren. Nimm einen iterator und iteriere durch die Liste, bis const_iterator(iter) == pos :p
-
Kellerautomat schrieb:
Du kannst es auch ohne const_cast implementieren. Nimm einen iterator und iteriere durch die Liste, bis const_iterator(iter) == pos :p
Es müsste intern vielleicht einen Weg geben, einen
const_iteratorzu einemiteratorumzuwandeln. Vielleicht einen privaten Konvertierungskonstruktor...
-
Noe, dann koennte man einen const_iterator ueber eine const list in einen iterator konvertieren. Der const_cast in erase ist schon korrekt so.
-
@K11t: Es spricht nichts gegen eine Konvertierungsfunktion.
template <typename C> iterator to_iterator(C& c, typename C::const_iterator it) { return c.erase(it,it); } template <typename C> iterator to_iterator(C& c, typename C::iterator it) { return it; }Schöner wäre natürlich, wenn erase nicht so einen Sonderstatus hat und mit to_iterator implementiert wäre (das wiederum die Logik enthielte).
-
http://ideone.com/Mrp6DC die gröbsten Fehler beseitigt, hoffe ich. sort und merge sind noch zu lang.
-
static_assert( std::is_same<T, typename std::allocator_traits<Allocator>::value_type>::value, "Allocator does not match value_type" );Warum?
Ich habe mir bis erst einmal nen Allocator selbst geschrieben und habe ihn mit std::map verwendet - und da habe ich einfach einen alloc<bool> verwendet weil ich eh weiß dass er rebinded wird und alloc<std::pair<std::string, std::vector<datastd::string>>> irgendwie unnötig hässlich ist.Ist es hier sogar falsch? Immerhin verwendest du ja die allocator_traits um mit möglichen sehr exotischen Allokatoren kompatibel zu sein die reference nicht als T& bzw pointer nicht als T* deklarieren (oä.).
Jedenfalls ist ein Pointer auf das data Element von node<T> immer T* - das T wird ja nicht vom Allokator alloziert sondern node<T>.
-
Ethon schrieb:
static_assert( std::is_same<T, typename std::allocator_traits<Allocator>::value_type>::value, "Allocator does not match value_type" );Warum?
Ich habe mir bis erst einmal nen Allocator selbst geschrieben und habe ihn mit std::map verwendet - und da habe ich einfach einen alloc<bool> verwendet weil ich eh weiß dass er rebinded wird und alloc<std::pair<std::string, std::vector<datastd::string>>> irgendwie unnötig hässlich ist.Ist es hier sogar falsch? Immerhin verwendest du ja die allocator_traits um mit möglichen sehr exotischen Allokatoren kompatibel zu sein die reference nicht als T& bzw pointer nicht als T* deklarieren (oä.).
Jedenfalls ist ein Pointer auf das data Element von node<T> immer T* - das T wird ja nicht vom Allokator alloziert sondern node<T>.Wenn ich mir 23.2.1/3 anschaue, muss value_type passen. Ausserdem muss ich das nochmal umschreiben
n3337 schrieb:
23.2.1/3
For the components affected by this subclause that declare an allocator_type, objects stored in these
components shall be constructed using the allocator_traits<allocator_type>::construct function and
destroyed using the allocator_traits<allocator_type>::destroy function (20.6.8.2). These functions
are called only for the container’s element type, not for internal types used by the container. [ Note: This
means, for example, that a node-based container might need to construct nodes containing aligned buffers
and call construct to place the element into the buffer. —end note]und es macht möglicherweise doch Sinn, ein Objekt beider Allokatortypen zu behalten, um nicht bei jeder Allokation eine Konvertierung vornehmen zu müssen.
Allokation mit allocator_traits<node_allocator>::allocate
Konstruktion mit allocator_traits<allocator_type>::construct für das DatenelementMit einer C++03-map kannst du möglicherweise einen falschen Allokator als Templateargument verwenden, in C++11 sollte das ausgeschlossen sein.
-
Ungefähr so müsste es korrekt sein.
Wie ein Copy-/Move-Zuweisungsoperator auszusehen hat, der propagate_on_container_copy_assignment/propagate_on_container_move_assignment umsetzt, ist mir noch nicht klar.
-
std::addressof( node->data() )
std::allocator_traits<ConstructAllocator>::address( constr, node->data() )Edit: Oh! Die Memberfunktion
addressist wohl ein Goodie vonstd::allocator.