Quando dovrei usare string_view in un'interfaccia?

14

Uso una libreria interna progettata per imitare un proposta libreria C ++ , e qualche volta negli ultimi anni vedo la sua interfaccia modificata dall'uso di std::string a string_view .

Quindi devo doverosamente modificare il mio codice, per conformarmi alla nuova interfaccia. Sfortunatamente, quello che devo passare è un parametro std :: string, e qualcosa che è un valore di ritorno std :: string. Quindi il mio codice è cambiato da qualcosa del genere:

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   api.setup (p1, special_number_to_string(p2));
}

a

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   const std::string p2_storage(special_number_to_string(p2));
   api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size()));
}

I veramente non vedo che cosa questo cambiamento mi ha comprato come client API, a parte un maggior numero di codice (probabilmente per rovinare). La chiamata dell'API è meno sicura (a causa dell'API che non possiede più la memoria per i suoi parametri), probabilmente ha salvato il mio programma 0 (a causa dell'ottimizzazione dello spostamento che i compilatori possono fare ora) e anche se salvasse il lavoro, sarebbe solo un paio di allocazioni che non verranno e non verranno mai eseguite dopo l'avvio o in un grande ciclo da qualche parte. Non per questa API.

Tuttavia, questo approccio sembra seguire i consigli che vedo altrove, ad esempio questa risposta :

As an aside, since C++17 you should avoid passing a const std::string& in favor of a std::string_view:

Trovo sorprendente questo consiglio, in quanto sembra sostenere la sostituzione universale di un oggetto relativamente sicuro con uno meno sicuro (fondamentalmente un puntatore e una lunghezza glorificati), principalmente ai fini dell'ottimizzazione.

Quindi quando dovrebbe string_view essere usato, e quando non dovrebbe?

    
posta T.E.D. 16.01.2018 - 21:21
fonte

3 risposte

14
  1. La funzionalità che assume il valore deve assumere la proprietà della stringa? Se è così usa std::string (non-const, non-ref). Questa opzione ti dà la possibilità di spostarti esplicitamente in un valore anche se sai che non verrà mai più utilizzato nel contesto di chiamata.
  2. La funzionalità legge semplicemente la stringa? Se è così usa std::string_view (const, non-ref) questo perché string_view può gestire std::string e char* facilmente senza problemi e senza fare una copia. Questo dovrebbe sostituire tutti i parametri const std::string& .

In definitiva dovresti mai dover chiamare il costruttore std::string_view come sei. std::string ha un operatore di conversione che gestisce la conversione automaticamente.

    
risposta data 16.01.2018 - 21:45
fonte
11

Un std::string_view porta alcuni dei vantaggi di un const char* in C ++: a differenza di std::string , a string_view

  • non possiede memoria,
  • non alloca memoria,
  • può puntare in una stringa esistente con un certo offset e
  • ha un livello inferiore di puntatore indiretto rispetto a std::string& .

Ciò significa che una string_view può spesso evitare copie, senza dover affrontare i puntatori grezzi.

Nel codice moderno, std::string_view dovrebbe sostituire quasi tutti gli usi dei parametri di funzione const std::string& . Questa dovrebbe essere una modifica compatibile con l'origine, poiché std::string dichiara un operatore di conversione a std::string_view .

Solo perché una vista a stringa non aiuta nel tuo caso d'uso specifico dove devi creare una stringa comunque non significa che sia una cattiva idea in generale. La libreria standard C ++ tende ad essere ottimizzata per generalità piuttosto che per comodità. L'argomento "meno sicuro" non regge, in quanto non dovrebbe essere necessario creare la vista stringa da soli.

    
risposta data 16.01.2018 - 21:48
fonte
6

I find that advice surprising, as it seems to be advocating universally replacing a relatively safe object with a less safe one (basically a glorified pointer and length), primarily for purposes of optimization.

Penso che questo sia un po 'equivoco allo scopo di questo. Anche se si tratta di un "ottimizzazione", dovresti davvero pensare a come liberarti dal dover utilizzare un std::string .

Gli utenti di C ++ hanno creato dozzine di diverse classi di stringhe. Classi di stringhe di lunghezza fissa, classi ottimizzate per SSO con la dimensione del buffer come parametro del template, classi di stringhe che memorizzano un valore di hash utilizzato per confrontarle, ecc. Alcune persone usano persino stringhe basate su COW. Se c'è una cosa che i programmatori C ++ amano fare, è scrivere classi di stringhe.

E ciò ignora le stringhe create e possedute dalle librerie C. Nudo char* s, forse con una dimensione di qualche tipo.

Quindi, se stai scrivendo una libreria e prendi un const std::string& , l'utente deve ora prendere qualsiasi stringa che stavi utilizzando e copiarlo su std::string . Forse dozzine di volte.

Se vuoi accedere all'interfaccia specifica per stringa di std::string , perché dovresti dover copiare la stringa? È un tale spreco.

I principali motivi per non prendere un string_view come parametro sono:

  1. Se il tuo obiettivo finale è passare la stringa a un'interfaccia che accetta una stringa terminata da NUL ( fopen , ecc.). std::string è garantito come NUL terminato; string_view non lo è. Ed è molto semplice sottostrare una vista per renderla non terminata NUL; sottostringa un std::string copierà la sottostringa in un intervallo terminato da NUL.

    Ho scritto uno speciale tipo di stile string_view con terminazione NUL proprio per questo scenario. Puoi fare la maggior parte delle operazioni, ma non quelle che interrompono il suo stato terminato da NUL (tagliare dalla fine, per esempio).

  2. Problemi a vita. Se hai davvero bisogno di copiare std::string o altrimenti la matrice di caratteri sopravvive alla chiamata di funzione, è meglio dichiarare questo in anticipo prendendo un const std::string & . O solo un std::string come parametro di valore. In questo modo, se hanno già una stringa di questo tipo, puoi rivendicarne la proprietà immediatamente e il chiamante può spostarsi nella stringa se non è necessario conservarne una copia in giro.

risposta data 17.01.2018 - 07:33
fonte

Leggi altre domande sui tag