API per la struttura dati con indici, size_t vs int?

2

Per una struttura dati con indici (ad esempio un elenco di array, un array dinamico, ecc ...), gli indici dovrebbero essere di tipo size_t o int ? C'è una ragione chiara per usare l'una sull'altra?

fooGetByIndex(struct foo* foo, size_t index);

o

fooGetByIndex(struct foo* foo, int index);

Finché non mi è stato suggerito di utilizzare size_t , sono sempre stato impostato su int senza pensarci troppo. Dopo aver sperimentato entrambi non sono abbastanza sicuro di quale sia l'API migliore.

Esistono molte discussioni su size_t vs int su un livello più generale, e non è quello che sto chiedendo. Mi interessa il caso più specifico di progettare un'API per una struttura dati che utilizza indici (vale a dire array-like) ma astrae l'accesso diretto all'array attraverso un'API.

Semanticamente size_t è appropriato per gli indici di array C, che è l'argomento principale per questo in questo caso. Tuttavia, se l'array C è nascosto dietro un'API (che potrebbe non usarne nemmeno uno internamente) tale argomento diminuisce. Inoltre, la possibilità di restituire -1 come valore di errore è molto più semplice quando si utilizza int , mentre (size_t)-1 è probabilmente più soggetto a errori e confuso per l'utente dell'API, nonostante sia ben definito e persino utilizzato dal C libreria standard nella sua funzione mbstowcs .

Se pertinente, le due API a cui sto lavorando possono essere trovate su CodeReview qui e qui , anche se sto cercando una risposta che si applichi alla progettazione API di strutture di dati basate su indici in generale, non solo a questi due esempi.

In questo caso sta utilizzando o size_t o int design API migliore o entrambi sono ugualmente validi (cioè la scelta è soggettiva)?

    
posta Wingblade 29.03.2018 - 18:37
fonte

2 risposte

2

Preferirei chiaramente size_t, poiché è un intero senza segno e gli indici sono > = 0. Sai immediatamente come usare questo parametro.

Non è uno stile valido restituire valori speciali come -1 per condizioni di errore. Ciò richiederà un codice aggiuntivo per il controllo. Se dimentichi questi controlli in alcuni punti, ciò può causare problemi di individuazione.

Dovresti utilizzare un metodo alternativo per la gestione degli errori, ad esempio:

  • Genera un'eccezione:

  • Se ad es. richiedere un indice, è possibile restituire la condizione di errore in base al valore restituito e all'indice in base alla posizione del parametro:

    bool GetMyIndex (size_t &result);
    

    Utilizzo:

    size_t returned_index = 0;
    if (!GetMyIndex(returned_index))
    {
        // handle the error
    }
    
risposta data 04.04.2018 - 13:28
fonte
0

Ci sono vari vantaggi per ciascuno dei possibili approcci.

Usare un solo tipo per tutti gli indici è bello, consentendo di passare un puntatore a un indice, o in C ++ un riferimento a un indice, in giro senza doversi preoccupare di ciò che si sta indicizzando esattamente.

Avere un indice non firmato è bello se i valori dell'indice non possono essere mai negativi.

Avere un indice con segno è bello perché significa che non devi essere paranoico con loop come for (i = count - 1; i > = 0; --i). E puoi usare -1 per implicare un indice non valido.

Non avere restrizioni artificiali a causa del tipo di indice è bello. È spazzatura usare un indice int su una macchina da 64 GB che potrebbe facilmente gestire indici molto più grandi.

Non sprecare spazio è bello. È spazzatura avere un indice a 64 bit che può accedere solo a uno dei due elementi.

    
risposta data 07.04.2018 - 11:45
fonte

Leggi altre domande sui tag