2012-11-16 14 views
8

A volte, quando sto programmando in C++, vorrei che ci fosse un valore undefined per ogni variabile come Javascript !. Per esempio, quando sto tornando un valore per l'elemento out-of-bounds di un array, è stato utile per restituire un undefined invece di lanciare un'eccezione, o:Restituzione di un riferimento non valido

template <typename T, int SIZE> 
class MyArray 
{ 
    T arr[SIZE]; 
    static T badref; 
public: 
    T &operator[](int i) 
    { 
    if (i >=0 && i < SIZE) 
     return arr[i]; 
    else 
     throw std::string("OUT-OF-BOUNDS"); // or: return badref; !! 
    } 
}; 

Un altro sporco (a mio parere) l'opzione sta restituendo un riferimento di una variabile pre-defind come variabile di riferimento errata. So che non possiamo assegnare null o qualcosa di simile a una variabile di riferimento.

C'è un altro modello ben formato per restituire un riferimento in cui il chiamante ha la possibilità di scoprire che il valore restituito non è valido?

EDIT: Non sto intendo un pointer

+5

Sì, si chiama un puntatore. In alternativa, 'boost :: opzionale'. – chris

+2

Almeno rendere statico l'oggetto badref, quindi non occuperà spazio in ogni MyArray creato. Ma sono d'accordo, è brutto. In un codice generico come quello vorrei piuttosto lanciare un'eccezione – john

+0

@john: Sì, l'ho modificato. – deepmax

risposta

5

È possibile usare boost :: opzionale come @ Chris menzionato nel suo commento. Viene fornito come parte della libreria di Boost. Vedi this page per maggiori dettagli.

Modificato classe:

template <typename T, int SIZE> 
class MyArray 
{ 
    T arr[SIZE]; 
public: 
    optional<T&> operator[](int i) 
    { 
    if (i >=0 && i < SIZE) 
     return optional<T&>(arr[i]); 
    else 
     return optional<T&>(); 
    } 
}; 

Usage:

MyArray<int>() array; 
// fill array with data 

optional<int&> result = array[0]; 
if (result) { 
    // item was found 
} else { 
    // index out of bounds 
} 
+0

cosa per badref? –

+0

@DenisErmolin Personalmente preferisco boost :: facoltativo, dal momento che afferma esplicitamente che il valore di ritorno di operator [] potrebbe essere indefinito e dovresti controllare questa condizione. –

+0

@MasoudM. Ho modificato la mia risposta e aggiunto il link per la documentazione. Puoi trovare ulteriori informazioni su Boost qui: http://www.boost.org/doc/libs/1_52_0/index.html –

2

Qualunque cosa si pensi di, la soluzione ha bisogno di adattarsi al tipo di sistema. Quindi la firma della tua funzione deve dire esplicitamente (in questo modo o in un altro) che il risultato potrebbe essere T, ma potrebbe anche essere qualcos'altro.

modi più comuni per questo sono:

  • Invece di restituire un valore, restituisce un codice di stato e di uscita il valore tramite un parametro "out" (un puntatore o riferimento):

    bool tryGet(int i, T& result); 
    
  • Restituisce una tupla (stato, valore) come:

    std::tuple<bool, T> get(int i) 
    

    (se c ouldn't ottenere, prendere in considerazione il secondo elemento tupla irrilevante - richiede T avere un costruttore di default)

  • Usa boost::variant (flessibile, ma richiede boost)

  • Usa boost::optional (versione più semplice di quanto sopra, quando si solo bisogno "T o niente")
3

Vorrei che ci fosse un valore indefinito per ogni variabile qualcosa come Javascript!

Si ha solo un valore "non definito" per i puntatori (nullptr). Un riferimento è (per definizione) qualcosa che punta a una valida istanza.

Per tornare un riferimento a un oggetto statico, è necessario separare tra i valori const e non const del proprio gestore:

template <typename T, int SIZE> 
class MyArray 
{ 
    T arr[SIZE]; 
    static T badref; 
public: 
    T &operator[](int i) 
    { 
    if (i >=0 && i < SIZE) 
     return arr[i]; 
    else 
     // returning ref here would allow clients to write: 
     // MyArray<int> a; 
     // a[-1] = 5; // valid if you return a non-const reference 
     throw std::string("OUT-OF-BOUNDS"); 
    } 
    const T &operator[](int i) const 
    { 
    if (i >=0 && i < SIZE) 
     return arr[i]; 
    else { 
     // MyArray<int> a; 
     // a[-1] = 5; // will not compile (cannot assign to const) 
     static const T invalid = T(); 
     return invalid; 
    } 
    } 

};

0

L'obiettivo principale dei riferimenti è evitare valori non validi (NULL) consentendo al tempo stesso alle funzioni di modificare i propri argomenti e impedire la copia dei dati. Se hai bisogno di un valore NULL, usa un puntatore.

Problemi correlati