Perché std :: ssize () è stato introdotto in C ++ 20?


99

C ++ 20 ha introdotto ilstd::ssize() funzione gratuita come di seguito:

template <class C>
    constexpr auto ssize(const C& c)
        -> std::common_type_t<std::ptrdiff_t,
                              std::make_signed_t<decltype(c.size())>>;

Una possibile implementazione sembra usare static_cast, per convertire il valore restituito dalla size()funzione membro di cl ass C nella sua controparte firmata.

Dal momento che il size() funzione membro di C restituisce sempre valori non negativi, perché qualcuno dovrebbe volerli memorizzare in variabili con segno? Nel caso in cui si voglia davvero, è una questione di semplice static_cast.

Perché è stato std::ssize()introdotto in C ++ 20?


4
@ Jarod42 L'implementazione non è definita invece che indefinita? (l'overflow con
segno

8
Se solo aggiungessero anche l' ssizeofoperatore.
geza

3
Questo potrebbe essere in qualche modo correlato: stackoverflow.com/questions/30395205/...
Marco13

10
@ JohnZ.Li A rischio di sembrare troppo poco costruttivo: penso che l'intero sistema dei tipi di C ++ per quanto riguarda i tipi interi sia rotto. Certo, si può sostenere che alcune stranezze (come non sapere quanti bit charha) sono ereditate da C e almeno un po 'alleviate da (u)intX_t, ma è ancora una fonte infinita di bug altrettanto sottili e critici. Cose come ssizesono solo patch, e ci vorrà del tempo (forse "per sempre") prima che questo affondi nelle comuni "guide alle migliori pratiche" che le persone (possono) seguire rigorosamente.
Marco13

6
@ Marco13: D'altra parte, il sistema di tipi C / C ++ (al contrario, ad esempio, del sistema di tipi fissi di Java), oltre a consentire al codice C / C ++ di funzionare su architetture in cui la maggior parte degli altri linguaggi gracchiano, consente agli istruttori competenti di ottenere alcune informazioni importanti lezioni nella testa di uno studente. Ad esempio, non tutto il mondo è a 64 bit. E no, non tutto il mondo usa caratteri a 8 bit. È estremamente facile far fronte a queste cose e ti rende uno sviluppatore migliore, se solo gli istruttori lo insegnassero dall'inizio . (E, solo per assicurarsi che, si fa sapere che i (u)intX_ttipi sono opzionali , vero?)
DevSolar

Risposte:


69

La logica è descritta in questo documento . Una citazione:

Quando span è stato adottato in C ++ 17, utilizzava un intero con segno sia come indice che come dimensione. In parte questo era per consentire l'uso di "-1" come valore sentinella per indicare un tipo la cui dimensione non era nota al momento della compilazione. Ma avere un contenitore STL la cui funzione size () restituiva un valore con segno era problematico, quindi è stato introdotto P1089 per "risolvere" il problema. Ha ricevuto il sostegno della maggioranza, ma non il margine di 2 a 1 necessario per il consenso.

Questo documento, P1227, era una proposta per aggiungere funzioni std :: ssize e membro ssize () non membri. L'inclusione di questi renderebbe un certo codice molto più semplice e consentirebbe di evitare indesiderate non firmate nei calcoli delle dimensioni. L'idea era che la resistenza a P1089 sarebbe diminuita se ssize () fosse stato reso disponibile per tutti i contenitori, sia tramite std :: ssize () che come funzioni membro.


30
L' for(int i = 0; i < container.ssize() - 1; ++i)esempio è anche abbastanza convincente
Caleth

7
@ John mi sembra davvero che potrebbero fare la stessa cosa di string :: npos e usare semplicemente size_t (-1) come valore speciale.
rubenvb

15
@ JohnZ.Li È da tempo considerato un errore che i tipi di dimensione STL non siano firmati. Ora purtroppo è troppo tardi per riformarlo. Fornire una funzione gratuita è il meglio che possiamo fare fin d'ora.
LF

16
@LF: Era Herb Sutter in una conferenza (forse lo ha detto anche Bjarne). Ma è un po 'sbagliato. Ora, con i computer a 32 bit / 64 bit, la dimensione del segno sarebbe migliore (quindi ha ragione). Ma ai vecchi tempi (dimensioni a 16 bit), la dimensione del segno sarebbe stata cattiva (ad esempio, avremmo potuto allocare solo array da 32k byte).
geza

11
@LF: Ho scoperto che Herb ha menzionato questo: youtube.com/watch?v=Puio5dly9N8&t=2667 . Quando dice che "non emerge molto in pratica", è vero al giorno d'oggi. Ma non era affatto vero> 20 anni fa (sistemi a 16 bit). Quindi, non è stato un grosso errore usare unsigned, quando è stato progettato l'STL.
geza

50

Gratuitamente rubato a Eric Niebler:

'Unsigned types signal that a negative index/size is not sane'era la saggezza prevalente quando l'STL è stato progettato per la prima volta. Ma logicamente, un conteggio delle cose non deve essere positivo. Potrei voler tenere un conteggio in un numero intero con segno per denotare il numero di elementi aggiunti o rimossi da una raccolta. Quindi vorrei combinarlo con le dimensioni della collezione. Se la dimensione della raccolta non è firmata, ora sono costretto a mescolare aritmetica firmata e non firmata, che è una fattoria di bug. I compilatori avvertono di questo, ma poiché il design dell'STL costringe praticamente i programmatori in questa situazione, l'avviso è così comune che la maggior parte delle persone lo disattiva. È un peccato perché questo nasconde veri bug.

L'uso di int senza segno nelle interfacce non è il vantaggio che molte persone pensano che sia. Se per sbaglio un utente passa un numero leggermente negativo all'API, improvvisamente diventa un enorme numero positivo. Se l'API avesse preso il numero come firmato, potrebbe rilevare la situazione affermando che il numero è maggiore o uguale a zero.

Se restringiamo il nostro uso di int senza segno al bit twiddling (ad esempio, maschere) e utilizziamo int con segno ovunque, è meno probabile che si verifichino bug e più facile da rilevare quando si verificano.


6
Swift adotta questo approccio, anche se non ha la preoccupazione che i numeri con segno negativo vengano reinterpretati come enormi numeri non firmati (dal momento che non ci sono cast impliciti, che sono ciò che ti porta davvero in questa folle casa divertente per cominciare). Prendono semplicemente l'approccio che (le dimensioni della parola macchina) Intdovrebbero essere i tipi di valuta comune dei numeri interi, anche dove solo i numeri positivi hanno senso (come l'indicizzazione di un array). Qualsiasi deviazione da esso dovrebbe essere fondata. È bello non doversi preoccupare dei cast ovunque.
Alexander - Ripristina Monica

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.