Newsgroup: it.comp.lang.c++
Titolo: string

Hi,
  ho deciso di  portare un mio programmino dal C  al C++, ovviamente
non  voglio limitarmi  ad  una semplice  ricompilazione, ma  intendo
riscriverlo in  puro stile "object  oriented" in modo da  rendere il
codice  più leggibile  e  mantenibile, in  questo  modo posso  anche
imparare questo bellissimo linguaggio :)
  Per cominciare sto iniziando a cambiare tutta la gestione stringhe
che usavo attualmente (interamente basata su puntatori di caratteri)
con la più comoda classe string.
  Purtroppo  non conosco  ancora bene  questa classe,  volevo quindi
chiedervi dove posso reperire info al riguardo...
  In particolare  mi interessava sapere  se, come mi sembra  di aver
intuito,  al posto  di strstr  devo usare  find... e  se esiste  una
funzione di ricerca di sottostringhe che non sia casesensitive.
  Attualmente usavo una funzione che mi ero scritto (strnoncasestr),
prima  di reinventare  la  ruota esiste  qualcosa  del genere  sulla
classe string?
p.s. una  soluzione  potrebbe  essere  quella di ereditare la classe
     string e aggiungere la mia funzioncina...
-- 
Vanni Brutto
| email 
za...@nofesso.libero.it
      |
| irc nick VanniB   |   ICQ 18526701 |
--- rimuovi nofesso per rispondere ---
---PC powered by Linux kernel 2.4.14vb
Un OS per trovarli, un OS per domarli,
Un  OS   per  ghermirli  e   nel  buio
incatenarli. 

      string e aggiungere la mia funzioncina...
Questo è proprio ciò che si farebbe in Java (ci dicevi che conosci già 
Java, vero?), ma in C++ la tendenza è di essere più cauti nel 
derivare. In questo caso, non ti serve tanto un nuovo tipo di dato, 
quanto un algoritmo di case unsensitive find: quindi io mi limiterei a 
fare l'overload della tua 'strnoncasestr' per trattare anche le 
std::string.
#include <iostream>
#include <string>
#include <cctype>
std::string::size_type strnoncasestr( std::string str, std::string parola )
{
  using namespace std;
  // pongo 'str' e 'parola' minuscole
  int len = str.length();
  for( int i=0; i<len; ++i )
    str[i] = tolower( str[i] );
  len = parola.length();
  for( int i=0; i<len; ++i )
    parola[i] = tolower( parola[i] );
  return str.find(parola);
} 
int main()
{
  std::cout << "pos: " << strnoncasestr( "FRASE", "as" ) << std::endl;
}
Nel caso avessi a che fare anche con altri tipi di stringa, potresti 
farne un template.
-- 
Ciao, Marvin

std::string::size_type strnoncasestr( std::string str, std::string parola )
                        ^^^
Gli identificatori inizianti per "str" sono riservati,
secondo lo standard, agli implementatori dei compilatori.
Per le proprie costruzioni, bisognerebbe usare un prefisso
diverso.

 derivare.
Ok, però le abitudini sono dure a morire :(
Nel frattempo  mi ero fatto  la mia  piccola classe che  ho chiamato
zstring (non c'è un motivo per cui ho scelto la z iniziale).
Mi  sono  trovato  di  fronte   ad  un  nuovo  problema,  l'overload
dell'operatore  =, da  quanto ho  capito  quando si  eredita da  una
classe l'operatore =  non viene ereditato, mentre ciò  avviene per i
restanti operatori... è corretto o ho capito male?
Ho anche letto  una soluzione proposta (dalla quale  ho preso spunto
per  il  codice  che  segue),  non  è che  mi  potreste  dire  se  è
formalmente correta?  Come mai questa  scelta del linguaggio  di non
ereditare l'overload dell'operatore?
Cmq ora  ho abbastanza materiale  per poter iniziare a  riscrivere i
miei programmini in C++, grazie davvero a tutti!
#v+
<code>
class zstring:public string {
        public:
          zstring &operator = (const string &str)
          {
            string::operator = (str);
            return *this;
          }
          int findnoncase (const char *str);
          int findnoncase (zstring str);
};
</code>
#v-
p.s. ho evitato di postare  il codice di findnoncase perché potreste
     inorridirvi :)
-- 
Vanni Brutto
| email 
za...@nofesso.libero.it
      |
| irc nick VanniB   |   ICQ 18526701 |
--- rimuovi nofesso per rispondere ---
---PC powered by Linux kernel 2.4.14vb
E' la donna che  sceglie l'uomo che la
sceglierà. 

funzione di ricerca di sottostringhe che non sia casesensitive.
No, devi costruirtela.
Ti basta convertire o tutto in minuscolo o tutto in
maiuscolo e compiere la ricerca.

      string e aggiungere la mia funzioncina...
potrebbe essere una soluzione, ma devi andarci cauto, dato che 
std::string non ha il distruttore virtuale; ad esempio
class Prova: public std::string {};
void foo()
{
        std::string* s = new Prova;
        delete s; // undefined behaviour
}
Lo standard specifica che se la classe base non ha distruttore 
virtuale, il comportamento del codice qua sopra e' indefinito.
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 restanti operatori... è corretto o ho capito male?
L'operatore di assegnamento della classe base *e'* ereditato, ma e'
nascosto da quello sintetizzato dal compilatore per la sottoclasse (o da
quello che hai definito tu). In pratica l'unico modo per richiamarlo e',
come hai gia' scoperto, la notazione esplicita.
Ciao,
Nicola

     string e aggiungere la mia funzioncina...
Occhio,perché la classe basic_string non é una classe pensata per
effettuare derivazioni,ma bensi' specializzazioni, e quella di
effettuare una derivazione potrebbe non essere una buona idea.
Molto meglio usare una funzione.
Il Ghenio
---------
These are my parting words to you:
those who give up are doomed!

 virtuale, il comportamento del codice qua sopra e' indefinito.
Perchè indefinito ? Non dovrebbe richiamare il distruttore string::~string( 
) ?
( Che poi possa essere scorretto, siamo daccordo ! )

) ?
No, secondo lo standard, il comportamento e' indefinito.
-- 
Andrea Laforgia
#exclude <windows.h>

 string::~string( ) ?
questo e' quello che succede normalmente. Ma tecnicamente e' undefined 
behaviour; cfr Scott Meyers, "Effective C++", Item 14
ciao anto


 behaviour; cfr Scott Meyers, "Effective C++", Item 14
C'è un motivo per cui si ricade nel "undefined behaviour" ?

 C'è un motivo per cui si ricade nel "undefined behaviour" ?
se hanno deciso che fare questo provoca un undefined behaviuor anziche' 
un piu' sicuro "chiama il dtor della classe base" probabilmente ci sono 
delle archietetture in cui questo avrebbe portato a delle perdite di 
efficienza. Ma non ti saprei dire proprio quali...
ciao Anto


 efficienza. Ma non ti saprei dire proprio quali...
Non è una questione di efficienza o di architetture. E' una questione di
operazione indefinita.
Non fare confusione fra la "delete expression" e l' "operator delete"
che sono due cose molto ma molto diverse.
Quando fai la delete di un puntatore ad una classe base che non
definisce un distruttore virtuale, l'espressione di delete non è in
grado di operare correttamente.
Nota che l'espressione delete deve provocare due cose: la chiamata del
corretto distruttore e la chiamata del corretto operator delete. Nessuna
di queste due cose è possibile nel caso specifico. Il distruttore
corretto non può essere chiamato perchè sconosciuto (potrebbe essere
chiamato il distruttore della classe base, ma non è detto che questo sia
sufficente a distruggere correttamente l'oggetto). L'operator delete
corretto non può essere conosciuto. Si portebbe chiamare l'operator
delete globale, ma non è detto che questo sia quello giusto. Inoltre non
è neppure detto che l'indirizzo passato all'operator delete sia quello
giusto. Immagina questo caso: la classe B1 ha dei membri dati. La classe
B2 ha dei membri dati e NON ha funzioni virtuali (neppure il
distruttore). La classe D deriva prima da B1 e poi da B2 (multiple
inheritance) e inoltre dichiara operatori di new e delete speciali (come
membri della stessa classe). L'indirizzo di un oggetto allocato
dinamicamente come tipo D (e pertanto allocato sull'heap privato
speciale definito dagli operatori new/delete della classe D) viene
convertito in un puntatore a B2 e questo appare nella delete expression.
Non solo non vengono richiamati i distruttori della classe B1 e D ma non
viene neppure usato il corretto operator delete. L'operator delete
globale si vede passare un indirizzo che non fa parte del suo heap.
Peggio: non è neppure il vero indirizzo dell'oggetto! Ammesso e non
concesso che l'operator new e delete membri della classe D facciano di
fatto riferimeno a quelli globali, l'indirizzo passato non è quello
allocato ma quello del sottooggetto B2!
Quindi come vedi la delete expression con un puntatore ad una classe
base che non ha distruttore virtuale, qualora il puntatore punti a una
classe derivata, non puù che essere un qualcosa di del tutto indefinito.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556