 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Oliver S. Guest
|
Posted: Sun Oct 23, 2005 5:42 am Post subject: Der lallocator<T> |
|
|
Ich hab ja wie bereits in einem Vorangegangenen Posting gesagt eine
Aversion gegen std::string, denn wenn das Teil mit dem std::allocator
arbeitet, dann ist die Performance auf eigentlich allen Implementatio-
nen ziemlich schlecht im Vergleich zu einfachen C-Strings auf dem Stack.
Alerdings ist std::string natülich um eine Größenordnung einfacher in
der Handhabung und ermöglicht Buffer-Overflow-freien Code bei korrekter
Benutzung einfacher als das mit C-Strings möglich wäre.
Daher dachte ich mir, daß ich mir einen eigenen Allocator bastle, der
mit Buffern arbeitet die auf dem Stack liegen. Die Buffer dieses Allo-
cators sollten sowohl in ihrer Anzahl als auch in ihrer Größe konfigu-
rierbar sein. Sollte eine Allokations-Anforderung fehlschlagen weil
der Allocator keinen eigenen Buffer mehr vorfindet oder die Buffer
zu klein sind, dann solte er in solchen Fällen zu std::allocator<T>
als Fallback zurückgreifen.
Man könnte jetzt hingehen und einen Allocator basteln der als Template
-Parameter den Basis-Typen, Größe und die Anzahl der internen Buffern
hat. Das würde aber für jede Konstellation dieser Parameter eine Menge
Code-Bloat erzeugen und das noch ausweiten weil für jede dieser mögli-
chen Konstellationen ein eigener STL-Container kompiliert würde. Daher
habe ich mich dafür entschieden, einen Allocator zu definieren der als
Konstruktor-Parameter eine Referenz auf ein Interface eines Buffers
erhält (wie man sieht ist mein lallocator von std::allocator abgeleitet
um eine Menge Datentypen und Methoden nicht selbst definieren zu müs-
sen):
template<typename T>
class lallocator : public std::allocator<T>
{
public:
lallocator( lallocator_buffer_if<T> *plbi );
//...
};
Die Klasse für das lallocator-Buffer-Interface sieht im wesentlichen
so aus:
template<typename T>
class lallocator_buffer_if
{
protected:
template<typename T>
friend class lallocator;
lallocator_buffer_if() {}
T *pop_buffer();
void push_buffer( T *pt );
bool is_yours( T *pt );
};
Der lallocator ist also ein Freund dieser Klasse damit er die internen
Methoden pop_buffer, push_buffer und is_yours verwenden kann. pop_buffer
holt einen Buffer und reserviert sich den (intern sind die Buffer als
ein Stack verkettet), push_buffer gibt den wieder zurück und is_yours
ist da damit der lallocator nachfragen kann ob ein ein Zeiger zu einem
der internen Buffern gehört; damit kann er erkennen ob ein Block bei
einer deallocate()-Operation über einen Buffer befriedigt werden konnte
oder der über den std::allocator<T>-Fallback beschafft werden musste um
somit den Block ggf bei std::allocator<T>::dealocate() abzugeben.
Von dem lallocator_buffer_if ist dann die konkrete Buffer-Klasse abge-
leitet die als Template-Parameter den Datentypen, die Anzahl der Buffer
und die Größe eines Buffers enthält:
template<typename T, std::size_t buffers, std::size_t buffer_size>
class lallocator_buffer : public lallocator_buffer_if<T>
{
public:
lallocator_buffer();
//..
};
Der Konstruktor initialisiert private Elemente der Basisklasse lallo-
cator_buffer_if so daß diese weiß, wie groß die Buffer sind, wieviele
es davon gibt und wie sie diese Finden kann (es wird also der interne
Stack initialisiert).
Sieht doch nett, aus nicht? Und bringt STL-Operationen auf std::basic
_string<> sicher superschnell; so schnell, daß man damit in diese selbe
Größenordnung wie die C-Strings kommt.
So, und nun für die, die's interessier hier der komplette Source des
lallocators. Das Ding ist sicher noch nicht 100% STL-Konform, aber
sollten sich dadurch Probleme ergeben, so werde ich die ganze Sache
sicher noch aufblasen. Übrigens: bitte nicht weinen wenn ich religiö-
sen Ansprüchen an die C++-Konformität nicht gerecht geworden bin (hab
an einer Stelle etwas rumgetrickst).
template<typename T>
class lallocator_buffer_if
{
protected:
template<typename T, std::size_t buffers, std::size_t buffer_size>
friend class lallocator_buffer;
template<typename T>
friend class lallocator;
private:
lallocator_buffer_if() {}
T *pop_buffer();
void push_buffer( T *pt );
bool is_yours( T *pt );
protected:
union buffer_header
{
buffer_header *pbhNextFree;
T at[1];
};
protected:
std::size_t m_buffer_size;
buffer_header *m_pbhBufferEnd;
buffer_header *m_pbhFirstFree;
};
template<typename T>
inline
T *lallocator_buffer_if<T>::pop_buffer()
{
buffer_header *pbh;
if( (pbh = m_pbhFirstFree) == NULL )
return NULL;
return m_pbhFirstFree = pbh->pbhNextFree,
&pbh->at[0];
}
template<typename T>
inline
void lallocator_buffer_if<T>::push_buffer( T *pt )
{
buffer_header *pbh;
pbh = (buffer_header *)pt;
pbh->pbhNextFree = pbh;
m_pbhFirstFree = pbh;
}
template<typename T>
inline
bool lallocator_buffer_if<T>::is_yours( T *pt )
{
return (void*)pt >= (void *)this &&
pt < &m_pbhBufferEnd->at[0];
}
template<typename T, std::size_t buffers, std::size_t buffer_size>
class lallocator_buffer : public lallocator_buffer_if<T>
{
public:
lallocator_buffer();
private:
union buffer
{
buffer_header bh;
T at[buffer_size];
};
private:
buffer aBuffers[buffers];
};
template<typename T, std::size_t buffers, std::size_t buffer_size>
inline
lallocator_buffer<T, buffers, buffer_size>::lallocator_buffer()
{
buffer *pbuf,
*pbufNext;
for( (pbuf = &aBuffers[buffers - 1],
pbufNext = NULL);
pbuf >= aBuffers;
(pbuf -= 1,
pbufNext = pbuf) )
pbuf->bh.pbhNextFree = &pbufNext->bh;
m_buffer_size = buffer_size;
m_pbhBufferEnd = &aBuffers[buffers].bh;
m_pbhFirstFree = &aBuffers[0].bh;
}
template<typename T>
class lallocator : public std::allocator<T>
{
public:
lallocator( lallocator_buffer_if<T> *plbi );
lallocator( lallocator const &l );
~lallocator() {};
pointer allocate( size_type count, void *hint = NULL );
void deallocate( pointer ptr, size_type count );
lallocator &operator =( lallocator &la );
public:
template<class Other>
struct rebind
{
typedef lallocator<Other> other;
};
private:
lallocator_buffer_if<T> *m_plbi;
};
template<typename T>
inline
lallocator<T>::lallocator( lallocator_buffer_if<T> *plbi ) :
std::allocator<T>()
{
m_plbi = plbi;
}
template<typename T>
inline
lallocator<T>::lallocator( lallocator const &l ) :
std::allocator<T>( l )
{
m_plbi = l.m_plbi;
}
template<typename T>
inline
typename lallocator<T>::pointer lallocator<T>::allocate( size_type count,
void *hint )
{
T *pt;
if( count > m_plbi->m_buffer_size ||
(pt = m_plbi->pop_buffer()) == NULL )
return std::allocator<T>::allocate( count ); // , hint );
return pt;
}
template<typename T>
inline
void lallocator<T>::deallocate( pointer ptr, size_type count )
{
if( !m_plbi->is_yours( ptr ) )
return std::allocator<T>::deallocate( ptr, count );
m_plbi->push_buffer( ptr );
}
template<typename T>
inline
typename lallocator<T> &lallocator<T>::operator =( lallocator &la )
{
plb = la.plb;
}
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Oliver S. Guest
|
Posted: Mon Oct 24, 2005 6:12 pm Post subject: Re: Der lallocator<T> |
|
|
Scheiße, hab das Ding etwas auf die Schnelle runtergeschrieben und
dabei zwei fette Bugs einebaut - und das bei so einer einfachen Sache.
Zu meiner Ehrenrettung muss ich aber sagen, daß ich schon fast 15h
programmiert hatte als ich das Ding gebastelt hatte (ich bin nicht
erst aufgestanden als ich um 7:Irgendwas Uhr das Ding gepostet habe.
Daher hier die gefixte Version:
template<typename T>
class lallocator_buffer_if
{
protected:
template<typename T, std::size_t buffers, std::size_t buffer_size>
friend class lallocator_buffer;
template<typename T>
friend class lallocator;
private:
lallocator_buffer_if() {}
T *pop_buffer();
void push_buffer( T *pt );
bool is_yours( T *pt );
protected:
union buffer_header
{
buffer_header *pbhNextFree;
T at[1];
};
protected:
std::size_t m_buffer_size;
buffer_header *m_pbhFirstFree;
buffer_header *m_pbhBufferEnd;
};
template<typename T>
inline
T *lallocator_buffer_if<T>::pop_buffer()
{
buffer_header *pbh;
if( (pbh = m_pbhFirstFree) == NULL )
return NULL;
return m_pbhFirstFree = pbh->pbhNextFree,
&pbh->at[0];
}
template<typename T>
inline
void lallocator_buffer_if<T>::push_buffer( T *pt )
{
buffer_header *pbh;
pbh = (buffer_header *)pt;
pbh->pbhNextFree = m_pbhFirstFree;
m_pbhFirstFree = pbh;
}
template<typename T>
inline
bool lallocator_buffer_if<T>::is_yours( T *pt )
{
return (void*)pt >= (void *)this &&
pt < &m_pbhBufferEnd->at[0];
}
template<typename T, std::size_t buffers, std::size_t buffer_size>
class lallocator_buffer : public lallocator_buffer_if<T>
{
public:
lallocator_buffer();
private:
union buffer
{
buffer_header bh;
T atUnReferenced[buffer_size];
};
private:
buffer aBuffers[buffers];
};
template<typename T, std::size_t buffers, std::size_t buffer_size>
inline
lallocator_buffer<T, buffers, buffer_size>::lallocator_buffer()
{
buffer *pbuf,
*pbufNext;
for( (pbuf = &aBuffers[buffers - 1],
pbufNext = NULL);
pbuf >= aBuffers;
(pbufNext = pbuf,
pbuf -= 1) )
pbuf->bh.pbhNextFree = &pbufNext->bh;
m_buffer_size = buffer_size;
m_pbhBufferEnd = &aBuffers[buffers].bh;
m_pbhFirstFree = &aBuffers[0].bh;
}
template<typename T>
class lallocator : public std::allocator<T>
{
public:
lallocator( lallocator_buffer_if<T> *plbi );
lallocator( lallocator const &lc );
~lallocator() {};
pointer allocate( size_type count, void *hint = NULL );
void deallocate( pointer ptr, size_type count );
lallocator &operator =( lallocator const &lc );
public:
template<class Other>
struct rebind
{
typedef lallocator<Other> other;
};
private:
lallocator_buffer_if<T> *m_plbi;
};
template<typename T>
inline
lallocator<T>::lallocator( lallocator_buffer_if<T> *plbi ) :
std::allocator<T>()
{
m_plbi = plbi;
}
template<typename T>
inline
lallocator<T>::lallocator( lallocator const &lc ) :
std::allocator<T>( lc )
{
m_plbi = lc.m_plbi;
}
template<typename T>
inline
typename lallocator<T>::pointer lallocator<T>::allocate( size_type count,
void *hint )
{
T *pt;
if( count > m_plbi->m_buffer_size ||
(pt = m_plbi->pop_buffer()) == NULL )
return std::allocator<T>::allocate( count );
return pt;
}
template<typename T>
inline
void lallocator<T>::deallocate( pointer ptr, size_type count )
{
if( !m_plbi->is_yours( ptr ) )
return (void)std::allocator<T>::deallocate( ptr, count );
m_plbi->push_buffer( ptr );
}
template<typename T>
inline
typename lallocator<T> &lallocator<T>::operator =( lallocator const &lc )
{
return m_plbi = lc.m_plbi,
*this;
}
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Sun Oct 30, 2005 6:38 pm Post subject: Re: Der lallocator<T> |
|
|
Oliver S. wrote:
| Quote: | Daher dachte ich mir, daß ich mir einen eigenen Allocator bastle, der
mit Buffern arbeitet die auf dem Stack liegen. Die Buffer dieses Allo-
cators sollten sowohl in ihrer Anzahl als auch in ihrer Größe konfigu-
rierbar sein. Sollte eine Allokations-Anforderung fehlschlagen weil
der Allocator keinen eigenen Buffer mehr vorfindet oder die Buffer
zu klein sind, dann solte er in solchen Fällen zu std::allocator<T
als Fallback zurückgreifen.
|
(ohne das ganze Posting gelesen zu haben)
Hast Du schon mal was von der /Small String Optimization/ gehoert?
Ich wiss nicht, ob auch gcc schon damit einher kommt - allemal ist sie
Teil von STLport (und Vis C++ > 6).
Damit entfaellt Deine ganze Arbeit - denn warum willst Du denn Buffer
auf dem Stack mit einem Allokator und nicht direkt anlegen? Scheint
mir /l'art pour l'art/ (J Kanze wird mich sicherlich korrigieren, falls
dies nicht korrekt ist).
Das Konzept der /Small String Optimization/ ist, das Datum in einer
Union zu behalten - bis zu einer gewissen SIZE ist's ein Buffer auf dem
Stack, ansonsten wird ein Pointer/Speicher dynamisch angelegt.
union {
char* ptr_;
char array_[SIZE];
}
Ali
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Oliver S. Guest
|
Posted: Mon Oct 31, 2005 8:44 am Post subject: Re: Der lallocator<T> |
|
|
| Quote: | (ohne das ganze Posting gelesen zu haben)
|
Ooooh, schade!
| Quote: | Hast Du schon mal was von der /Small String Optimization/ gehoert?
Ich wiss nicht, ob auch gcc schon damit einher kommt - allemal ist sie
Teil von STLport (und Vis C++ > 6).
|
Ne, hab ich noch nicht von gehört.
| Quote: | Damit entfaellt Deine ganze Arbeit - denn warum willst Du denn Buffer
auf dem Stack mit einem Allokator und nicht direkt anlegen? Scheint
mir /l'art pour l'art/ (J Kanze wird mich sicherlich korrigieren, falls
dies nicht korrekt ist).
|
Weil aus dem Buffer-Pool halt viel schneller allokiert werden kann als
vom Heap.
| Quote: | Das Konzept der /Small String Optimization/ ist, das Datum in einer
Union zu behalten - bis zu einer gewissen SIZE ist's ein Buffer auf dem
Stack, ansonsten wird ein Pointer/Speicher dynamisch angelegt.
union {
char* ptr_;
char array_[SIZE];
}
|
Naja, das riecht mir garnicht so nach "general-purpose" weil ja entwerder
die maximale interne Grenze bei der Größe eines Pointers liegt, also weit-
gehend nicht gewinnbringend wäre, oder jeder String der sonstwo und überhalb
der maximalen internen Größe liegt unnötig mehr Speicher verbraucht; gefällt
mir *so* überhauptnicht! Besser wär es doch gewesen, man hätte std::basic
_string noch gleich einen zusätzlichen Parameter für die maximale interne
Größe mitgegeben; nur hätte das wieder einen heftigen Code-Bloat bedeutet
(den man über einen Trick aber wieder verringern hätte können).
Aber es gibt noch ein Problem das ich bei meiner Sache nicht beachtet habe:
Der C++-Standard verlangt von Allokatoren, daß man Speicher den man bei einem
Allokator bezogen hat, bei einem anderen typgleichen wieder freigeben kann.
Daher dürfen Allokatoren nicht stateful sein wenn sie 100% STL-konform sein
sollen:
"All instances of a given allocator type are required to be interchangeable
and always compare equal to each other."
Aber es gibt auch wiederum auch eine Ermunterung zu stateful Allokatoren in
der C++-Spezifikation:
"Implementors are encouraged to supply libraries that can accept allocators
that encapsulate more general memory models and that support non-equal in-
stances. In such implementations, any requirements imposed on allocators by
containers beyond those requirements that appear in Table 32, and the seman-
tics of containers and algorithms when allocator instances compare non-equal,
are implementation-defined."
Allerdings ist bei *völlständiger* Berücksichtigung von stateful Allokatoren
auf der ganzen Bandbreite der STL-Implementation nicht alles wirklich effi-
zient implementierbar, z.B. std::list<T,A>::splice().
Ich bin einfach mal hingegangen und hab meinen Allokator so eingeschränkt,
daß er immer false auf den operator == zurückgibt damit eine STL-Implemen-
tation z.B. in std::list<T,A>::splice() darauf assert()en könnte. Außerdem
gibt's bei mir keinen Default-Konstruktor damit die von den STL-Klassen
genutzten lallokatoren (geiles Wort, wa?) immer auf einen bestimmten Pool
zielen und ein rebind ist bei mir auch nur via Copy-Konstruktor auf den
selben Typen möglich auf den mein Allokator bei der jeweiligen STL-Klasse
"angemeldet" ist.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Mon Oct 31, 2005 6:50 pm Post subject: Re: Der lallocator<T> |
|
|
Oliver S. wrote:
| Quote: | Damit entfaellt Deine ganze Arbeit - denn warum willst Du denn Buffer
auf dem Stack mit einem Allokator und nicht direkt anlegen? Scheint
mir /l'art pour l'art/ (J Kanze wird mich sicherlich korrigieren, falls
dies nicht korrekt ist).
Weil aus dem Buffer-Pool halt viel schneller allokiert werden kann als
vom Heap.
|
Wohl war, aber ein char array[SIZE] liegt ebenfalls auf dem Stack, ohne
das ein Allokator noetig ist - das meinte ich mit direkt anlegen.
| Quote: | Naja, das riecht mir garnicht so nach "general-purpose" weil ja entwerder
die maximale interne Grenze bei der Größe eines Pointers liegt, also weit-
gehend nicht gewinnbringend wäre, oder jeder String der sonstwo und
überhalb
der maximalen internen Größe liegt unnötig mehr Speicher verbraucht;
|
Verstehe ich nicht ganz, Deine Logik: zB sei SIZE = 24. Dann ist jeder
String mit einer Laenge von (oBdA verwende ich einen Eintrag fuer ' ')
bis zu 23 Characters auf dem Stack, erst bei einer Laenge >= 24 wird
Speicher allokiert. Letzteres kostet Performance, aber spart evtl
Speicher - der uebliche Trade Off. Auf Arbeit verwenden wir zZt zB
SIZE=1024, da Performance den absoluten Vorrang hat).
Warum "verbraucht jeder String der sonstwo und überhalb der maximalen
internen Größe liegt unnötig mehr Speicher"?
Ali
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Oliver S. Guest
|
Posted: Mon Oct 31, 2005 7:48 pm Post subject: Re: Der lallocator<T> |
|
|
| Quote: | Naja, das riecht mir garnicht so nach "general-purpose" weil ja entwerder
die maximale interne Grenze bei der Größe eines Pointers liegt, also
weitgehend nicht gewinnbringend wäre, oder jeder String der sonstwo und
überhalb der maximalen internen Größe liegt unnötig mehr Speicher verbraucht;
Verstehe ich nicht ganz, Deine Logik: zB sei SIZE = 24. Dann ist jeder
String mit einer Laenge von (oBdA verwende ich einen Eintrag fuer ' ')
bis zu 23 Characters auf dem Stack, erst bei einer Laenge >= 24 wird
Speicher allokiert. Letzteres kostet Performance, aber spart evtl
Speicher - der uebliche Trade Off. Auf Arbeit verwenden wir zZt zB
SIZE=1024, da Performance den absoluten Vorrang hat).
Warum "verbraucht jeder String der sonstwo und überhalb der maximalen
internen Größe liegt unnötig mehr Speicher"?
|
Wenn ich ein String-Objekt nicht auf dem Stack, sondern in einer Daten-
struktur anlege die auf dem Heap liegt, dann sollte die Datenstruktur
möglichst kompakt sein damit der Heap möglichst gering belastet wird.
Ich möchte also entscheiden können: leg ich meinen String auf dem Stack
an, dann soll er etwas verschwenderisch mit dem Stack-Speicher umgehen
dürfen, soll er auf dem Heap liegen, dann soll er möglichst kompakt sein.
Habe ich aber eine Implementation mit identischem statischem Buffer für
alle Strings, dann muss ich den Overhead für diesen statischen Buffer
für alle Strings auf dem Heap akzeptieren.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Tue Nov 01, 2005 6:19 pm Post subject: Re: Der lallocator<T> |
|
|
Hm, ich bin immer noch nicht weiter mit dem Verstaendnis
Oliver S. wrote:
| Quote: | Warum "verbraucht jeder String der sonstwo und überhalb der maximalen
internen Größe liegt unnötig mehr Speicher"?
Wenn ich ein String-Objekt nicht auf dem Stack, sondern in einer Daten-
struktur anlege die auf dem Heap liegt, dann sollte die Datenstruktur
möglichst kompakt sein damit der Heap möglichst gering belastet wird.
|
Verstehe ich, mit der vorgeschlagenen Optimierung bekommst Du ja auch
genau das. Dein String-Objekt enthaelt einen Pointer auf ein
zusammenhaengendes Stueck Memory, wenn der Datenstring laenger als SIZE
ist.
| Quote: | Ich möchte also entscheiden können: leg ich meinen String auf dem Stack
an, dann soll er etwas verschwenderisch mit dem Stack-Speicher umgehen
dürfen
|
Ok, die angegebene Optimierung verrschwendet fuer kurze, dh auf dem
Stack liegende Strings SIZE-length Characters.
| Quote: | Habe ich aber eine Implementation mit identischem statischem Buffer für
alle Strings, dann muss ich den Overhead für diesen statischen Buffer
für alle Strings auf dem Heap akzeptieren.
|
Frage - wer hat denn eine /solche/ Loesung vorgeschlagen? Am besten, Du
schaust Dir den Vorschlag nocheinmal an. Ich sprach da von einer union
und nicht von einem pair<> oder struct (dh Du hast entweder einen
Pointer fuer lange Datenstrings *oder* einen Buffer (of size SIZE) fuer
kurze Datenstrings, aber niemals beide!).
Ali
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Oliver S. Guest
|
Posted: Wed Nov 02, 2005 6:15 pm Post subject: Re: Der lallocator<T> |
|
|
| Quote: | Wenn ich ein String-Objekt nicht auf dem Stack, sondern in einer Daten-
struktur anlege die auf dem Heap liegt, dann sollte die Datenstruktur
möglichst kompakt sein damit der Heap möglichst gering belastet wird.
Verstehe ich, mit der vorgeschlagenen Optimierung bekommst Du ja auch
genau das.
|
Ja, das bekomme ich wenn ich es will; aber ich bekomme es auch inklusive
aller Nachteile wenn ich es nicht will, und der Fall ist mit Sicherheit
häufiger als daß ich die Vorteile von einem internen Buffer brauche. Ich
will den statischen Buffer nur wenn zwei Bedingungen zutreffen:
1. Die Allokation und Deallokation des expliziter Buffers beim Anlegen
oder bei Operationen auf Strings kostet so viel Rechenzeit, daß die
Sache Laufzeit-kritisch wird und dieses Problem schwerer wiegt als
ein möglicherweise ungenutzter Buffer (weil der String in Einzelfällen
doch wieder zu lang wurde)
und
2. Der interne String-Buffer kommt auch häufig genug zum Zuge, kann
also im gewünschten Maße Allokationen und Deallokationen vermeiden
um somit Rechenzeit zu sparen.
Ich wage zu bezweifeln, daß das mit den Mini-Buffern von 16 Zeichen
scon gewährleistet ist.
| Quote: | Dein String-Objekt enthaelt einen Pointer auf ein zusammenhaengendes
Stueck Memory, wenn der Datenstring laenger als SIZE ist.
|
Ja, aber SIZE ist entweder so mickrig, daß es häufig nicht hilft oder
so groß, daß es bei String-Objekten im Heap unnötig Speicher frisst
(auf dem Stack dürfte fast immer der Verbrauch eines solchen internen
Buffers keinen interessieren).
| Quote: | Ich möchte also entscheiden können: leg ich meinen String auf dem Stack
an, dann soll er etwas verschwenderisch mit dem Stack-Speicher umgehen
dürfen
Ok, die angegebene Optimierung verrschwendet fuer kurze,
dh auf dem Stack liegende Strings SIZE-length Characters.
|
Auf dem Stack interessiert das meistens nicht - aber im Heap interessiert
das, denn wenn da eine nennenswerte Anzahl von Strings liegt, dann wird der
statishe Interne Puffer (der wie gesagt für alle Objekte gleich ist - was
schon totaler Käse ist) häufig nicht genutzt und verbrät unnötig Speicher.
| Quote: | Habe ich aber eine Implementation mit identischem statischem Buffer für
alle Strings, dann muss ich den Overhead für diesen statischen Buffer
für alle Strings auf dem Heap akzeptieren.
Frage - wer hat denn eine /solche/ Loesung vorgeschlagen?
|
Du hast mich missverstanden. Ich meinte nicht *einen* Statischen Buffer für
*alle* Strings, sondern *einen* Statischen Buffer pro String; identisch war
also in Bezug auf die Größe gemeint.
| Quote: | Am besten, Du schaust Dir den Vorschlag nocheinmal an. Ich sprach
da von einer union und nicht von einem pair<> oder struct (dh Du
hast entweder einen Pointer fuer lange Datenstrings *oder* einen
Buffer (of size SIZE) fuer kurze Datenstrings, aber niemals beide!).
|
Ist mir schon klar was Du meinst; aber das Konzept ist dennoch Scheiße.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Thu Nov 03, 2005 6:12 pm Post subject: Re: Der lallocator<T> |
|
|
Oliver S. wrote:
| Quote: |
Auf dem Stack interessiert das meistens nicht - aber im Heap interessiert
das, denn wenn da eine nennenswerte Anzahl von Strings liegt, dann wird der
statishe Interne Puffer (der wie gesagt für alle Objekte gleich ist - was
schon totaler Käse ist) häufig nicht genutzt und verbrät unnötig Speicher.
|
Ich versuch's nochmal Wenn Du SIZE = 16 waehlst, sehe ich nicht,
wo /unnoetig Speicher verbraten/ wird, es ist exakt das gleiche
Memory Layout fuer Strings > 16, wie wenn Du die Optimierung
weglaesst und die alte String-Implementierung verwendest.
| Quote: |
Habe ich aber eine Implementation mit identischem statischem Buffer für
alle Strings, dann muss ich den Overhead für diesen statischen Buffer
für alle Strings auf dem Heap akzeptieren.
Frage - wer hat denn eine /solche/ Loesung vorgeschlagen?
Du hast mich missverstanden.
|
Wieso?
| Quote: | Ich meinte nicht *einen* Statischen Buffer für
*alle* Strings, sondern *einen* Statischen Buffer pro String; identisch war
also in Bezug auf die Größe gemeint.
|
Genauso habe ich es verstanden - wo ist denn aber zB bei dem von
mir als Bsp gewaehltem Setup mit SIZE = 16 dieser von Dir erwaehnte
statische Buffer (pro String, ich weiss) fuer zB
string s("de.comp.lang.iso-c++");
? Ich sehe da einfach keinen.
Ali
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|