std::string: testo che si gestisce da solo
Nella pagina precedente hai visto come gli smart pointer permettono a un oggetto di possedere una risorsa e liberarla automaticamente. std::string è la stessa idea applicata al testo: possiede un buffer di caratteri, lo fa crescere quando aggiungi qualcosa e lo libera quando la stringa esce dallo scope. Non chiami mai new, non conti mai i byte e non ti preoccupi mai di un terminatore nullo mancante.
Per usarla, includi <string>. La classe si trova nel namespace std.
Quell'operatore + fa un lavoro vero: alloca un nuovo buffer abbastanza grande per entrambi i pezzi e li copia dentro. Con un char* grezzo, cioè un semplice puntatore a un buffer di caratteri, dovresti ricorrere a strcpy e strcat sperando che il buffer fosse abbastanza grande. std::string fa sparire tutta questa categoria di errori.
Costruire e unire stringhe
Puoi concatenare con +, ma lo strumento principale per far crescere una stringa sul posto è +=. Aggiunge al buffer esistente invece di produrre ogni volta una stringa nuova, e dentro i cicli questo conta.
Una sorpresa comune: + richiede che almeno uno degli operandi sia già una std::string. Due letterali stringa sono solo const char*, quindi "a" + "b" non compila: non esiste un operator+ per due puntatori grezzi. Trasforma prima uno dei due in una stringa:
string s = "a" + "b"; // error: can't add two const char*
string s = string("a") + "b"; // fine - left side is a std::string
string s = "a"s + "b"; // fine in C++14+, the "s" literal suffix
Nota che l'ultima forma usa il suffisso s di <string> (using namespace std::string_literals;), che trasforma un letterale direttamente in una std::string.
Accedere al contenuto di una stringa
Una std::string si comporta come un container di char, quindi puoi indicizzarla, ciclarci sopra e chiederne dei pezzi.
substr(pos, len) restituisce una stringa nuova copiata dall'originale; non modifica la sorgente. Attenzione ai limiti: word[10] su una stringa di 5 caratteri è undefined behavior. Non lancia eccezioni, legge solo spazzatura. Se vuoi un accesso controllato che lancia std::out_of_range, usa word.at(10) invece di word[10].
Un'altra trappola classica: .size() restituisce un tipo senza segno (size_t). Scrivere un ciclo all'indietro come for (size_t i = word.size() - 1; i >= 0; --i) non termina mai, perché una i senza segno non può mai scendere sotto zero: ricomincia da un numero enorme. Usa un indice con segno o riorganizza la condizione quando devi percorrere una stringa al contrario.
Cercare e sostituire
find individua una sottostringa o un carattere e restituisce l'indice iniziale. Quando l'obiettivo non c'è, restituisce la costante speciale std::string::npos: confronta sempre con quella invece di dare per scontato che find restituisca -1.
Per modificare il testo sul posto, replace(pos, len, text) sostituisce un tratto con un contenuto nuovo (che può avere una lunghezza diversa), e insert/erase aggiungono o rimuovono pezzi:
Stringhe e numeri
Testo e numeri non si convertono da soli: "42" sono tre caratteri, non l'intero 42. La libreria standard ti offre funzioni di conversione in entrambe le direzioni. Usa stoi, stod e simili per trasformare il testo in numeri, e to_string per la direzione opposta.
Due trappole qui. Primo, stoi("abc") lancia std::invalid_argument, quindi proteggi l'input non affidabile con un blocco try/catch. Secondo, to_string(3.99) produce il completo 3.990000: se ti serve controllare precisione e formattazione, è un compito per gli string stream, ed è proprio lì che andiamo adesso.
try {
int n = std::stoi(userInput);
} catch (const std::invalid_argument&) {
std::cout << "That wasn't a number.\n";
}
Prossimo passo: input e output
Hai sempre stampato stringhe con cout, ma leggerle dall'utente riserva le sue sorprese: cin >> name si ferma al primo spazio, quindi una riga intera come "Ada Lovelace" richiede invece std::getline. La prossima pagina tratta come si deve input e output in C++: operatori di stream, lettura di righe intere e come usare insieme >> e getline senza inciampare nei ritorni a capo rimasti nel buffer.
Domande frequenti
Qual è la differenza tra std::string e char* in C++?
std::string è una classe che possiede e gestisce la propria memoria, cresce quando serve e si ripulisce da sola. Un char* è solo un puntatore grezzo a dei caratteri terminati da '\0': il buffer, la lunghezza e la durata li gestisci tu. Preferisci std::string quasi sempre; elimina intere categorie di bug da buffer overflow e da puntatori pendenti.
Come si ottiene la lunghezza di una stringa in C++?
Chiama .size() o il suo alias .length() su una std::string: name.size() restituisce il numero di caratteri come size_t. Entrambi restituiscono lo stesso valore; size() è lo stile più comune perché è uguale a quello di ogni altro container della STL.
Come si converte una stringa in un numero in C++?
Usa std::stoi per int, std::stod per double e simili (stol, stof). Esempio: int n = std::stoi("42");. Queste funzioni lanciano std::invalid_argument se il testo non è un numero, quindi racchiudile in un try/catch quando l'input non è affidabile.