Newsgroup: it.comp.lang.c++
Titolo: Classe gestione stringhe c++

Salve, ho un problema e spero di trovare qui la soluzione.
Ho migrato un progetto da Borland a c++ ottenendo come principale
risultato un deterioramento delle performance.
Mediante appositi tools, noto che la gestione delle stringhe in
microsoft (cstring) è molto più lenta della gestione di borland (
ansistring ).
Questo perchè alla fin fine chiama costruttori e distruttori dell'atl.
Conosciete qualche classe di gestione stringhe efficiente da poter
includere facilmente nel mio progetto?
Potrei costruirla io ma non vorrei inventare l'acqua calda, magari
esiste già ed è stata testata.
Vi ringrazio anticipatamente
Byeeee

 includere facilmente nel mio progetto?
std::string

aerd...@gmail.com
 ha scritto:

Già provato grazie, addirittura leggermente peggiori delle cstring.
io cercavo una classe scritta anche in c che trattasse le stringhe, in
fondo le AnsiString di borland sono scritte in pascal/assembler e vanno
che è una cannonata rispetto alle microsoft

 io cercavo una classe scritta anche in c che trattasse le stringhe,
Il C non ha supporto per le classi e comunque non aggiungeresti nulla
in più rispetto alla gestione C++.  Va a finire che ti riscrivi la
classe std::string.


quantifico.
19/9/2006 14:55:9.  6 inizio Stringhe std string
19/9/2006 14:55:17.693 fine
19/9/2006 14:55:17.693 inizio Stringhe ansistring
19/9/2006 14:55:23.131 fine
19/9/2006 14:55:23.131 inizio date
La parte di codice di test è
	FmDMTrace(MSG_DM_DISPLAY_TIME, "inizio Stringhe std string");
	for( int j = 0; j < 1000000; ++j )
	{
   std::string  a =
"asdsafasfldklasòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòafqwkjrq2ljkrqwfdòqfamfqlkwrelqwmkrqwrmqwmrrmaps[j]
= j;";
   std::string  b = a;
	}
	FmDMTrace(MSG_DM_DISPLAY_TIME,"fine");
	FmDMTrace(MSG_DM_DISPLAY_TIME, "inizio Stringhe ansistring");
	for( int j = 0; j < 1000000; ++j )
	{
  Cstring  a =
"asdsafasfldklasòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòòafqwkjrq2ljkrqwfdòqfamfqlkwrelqwmkrqwrmqwmrrmaps[j]
= j;";
  Cstring b = a;
	}
Spero si capisca...

 Spero si capisca...
Si capisce che se tutto quello che fai con le stringhe e' assegnarle in
giro non stupisce che l'AnsiString Borland batta le altre (perlomeno
std::string) dal momento che usa reference count e copy on write. Il
tuo test pero' mi pare molto poco significativo.
In ogni caso puoi provare a guardare flex_string qui:
http://erdani.org/code/main.html
Ciao,
Nicola

 Nicola
Ho un progetto di diversi milioni di righe di codice.
Vuoi per i log, vuoi per messaggistica, facciamo miliardi di creazione,
concatenazione, assegnamento, distruzione stringhe.
Il mio esempio era per vedere quale classe di stringhe fosse più
efficente proprio nella creazione, concatenazione, assegnamento,
distruzione stringhe.
Visto che il mio obiettivo è avvicinarmi a borland, devo far si che
quel test impieghi lo stesso tempo che impiega l'eseguible borland

    std::string  b = a;
Questo non è un test significativo.

 tuo test pero' mi pare molto poco significativo.
Come siamo a thread safety? Ho paura che alcune implementazioni di 
stringhe tramite copy on write non siano totalmente safe, pero' non 
conosco i dettagli.
Ciao,
Zeppe


Da quel punto di vista siamo messi bene, c'è un server e tanti client
collegati adesso, ma le chamate vengono accodate quindi non c'è
multithread spinto.

 conosco i dettagli.
AFAIK, le AnsiString di Borland non sono thread-safe.

 distruzione stringhe.
Però, il tuo benchmark misura sostanzialmente la *creazione* di oggetti 
stringa. In particolare, la creazione a partire da letterale e la creazione 
a partire da altro oggetto stringa. La seconda è efficiente nelle 
implementazioni che usano il COW. Sarà però sufficiente modificare 
qualche carattere di 'b' per obbligare l'implementazione a duplicare la 
rappresentazione delle due stringhe e annullare i vantaggi del COW. 
Dovresti includere anche questa eventualità nel tuo test.
In generale, il COW è un'ottimizzazione che ha un peso quando la stringa 
viene restituita o passata per valore. Negli altri casi, un uso sapiente di 
'swap' ti permette di evitare copie inutii.
Concludo con un piccolo quiz. Secondo voi, se dobbiamo scrivere una 
funzione membro che riceve un 'std::string' e valorizza un membro dati di 
tipo 'std::string', quale delle due seguenti è preferibie (assumendo che 
non ci sia COW)?
    void func( const std::string& v ) // passaggio per riferimento const
    {  membro = v;                    // assegnamento
    }
    void func( std::string v )  // passaggio per valore
    {  membro.swap(v);          // swap
    }
Max

     }
La seconda.
Kiuhnm


Non ne sono convinto, ma forse mi sfugge qualcosa. Provo a descriverle
in pseudo codice:
La prima:
// Il passaggio per reference e' sostanzialmente una no-op.
if ( ! membro.empty() && ( v.empty() || membro.size() < v.size() ) )
  membro.dealloca();
if ( ! v.empty() ) {
  if ( membro.empty() )
    membro.alloca(v.size());
  membro.copia(v);
}
La seconda:
// Assumendo che sia chiamata come func(s);
if ( ! s.empty() ) {
  v.alloca(s.size());
  v.copia(s);
}
membro.swap(v);
if ( ! v.empty() )
  v.dealloca();
Io vedo un leggero vantaggio per la prima, nel caso in cui il buffer
sia sufficiente a contenere la stringa da copiare. Cosa mi son perso?
Ciao,
Nicola

 sia sufficiente a contenere la stringa da copiare. Cosa mi son perso?
Personalmente preferisco che le stringhe non sprechino memoria 
inutilmente (in generale).
Comunque la 2 si comporta meglio in caso di eccezioni. Se la funzione 
copia() genera un'eccezione, nella 1 perdi una parte di membro (e mi 
dicono che non è piacevole...). Lo so che copiare char non è rischioso, 
ma in generale potresti dover copiare oggetti più complessi.
Kiuhnm


Stavamo parlando di prestazioni e mi sono concentrato su quell'aspetto.
Sono d'accordo che la seconda e' l'unico modo di garantire che membro
non sprechi spazio. Sulla necessita'/opportunita' di garantire
comportamento transazionale in presenza di eccezioni, direi che dipende
dal contesto piu' generale, ma e' un problema che nel caso delle
stringhe, come dici, non si pone.
Ciao,
Nicola

     }
Dipende. In generale, direi que si asspetta piutosto una
riferenza che un valore per il parametro, mà che non ha molta
importanza. (Solo che non deve cambiare, anche se si cambia
l'implementazione della funzione.) Se no, non hanno le stesse
semantica. Si usa la prima quando si vuol la semantica della
prima, e la seconda quando se vuol la semantica della seconda.
E quando non importe, si usa la prima, perche è più "naturale"
(ed anche perche la sua semantica convienne più spesso?).
--
James Kanze                                           GABI Software
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, 
+33 (0)1 30 23 00 34

 > La seconda.




Ma dipende molto di più di quello che fai colla catena, non? Sto
pensando a un scanner, da essempio. func remette i caratteri non
consumati primo. Dopo, leggo i caratteri dal input, appendandoli
a membro. Colla la seconda versione, bisogna sempre delle nuove
allocazioni. Colla prima, una volta che ho letto il token il più
lungo, non che più di allocazioni.
Se guardo i miei membri di tipi string, ci sono molti cosi. Son
quasi i più frequenti fra i string mutabile. (I più frequenti
sono gl'identificatori o cose semblabile, che non cambiano dopo
la costruzione.)
In ogni caso, la prima mi sembra più "naturale". È dunque le chi
serva, fino che ho bisogna della semantica particulare della
seconda (che fà perdere tutti gli effetti d'un reserve() fatto
primo).


 sia sufficiente a contenere la stringa da copiare. Cosa mi son perso?
Quello che dici è corretto, nondimeno trovo che la seconda sia preferibile
perché ha prestazioni migliori nel caso in cui la funzione venga invocata
specificando come argomento un letterale stringa (che è in generale
un'eventualità piuttosto frequente).
Infatti, se argomento è un letterale stringa, la prima produce un ulteriore
std::string temporaneo; la seconda no.
Max

 std::string temporaneo; la seconda no.
A questo non avevo pensato.
Comunque, se il motivo è solo questo, conviene usare l'overloading.
Kiuhnm