Domanda

Sono abbastanza nuovo per C ++ quindi tendo a progettare con un sacco di Java-ismi mentre sto imparando. In ogni caso, in Java, se avessi classe con un metodo 'di ricerca' che restituisce un T oggetto da un Collection< T > che ha abbinato un parametro specifico, sarei tornato l'oggetto e se l'oggetto non è stato trovato nella collezione, vorrei tornare null . Poi nella mia funzione di chiamata vorrei solo verificare if(tResult != null) { ... }

In C ++, sto scoprendo che non posso restituire un valore null se l'oggetto non esiste. Voglio solo restituire un 'indicatore' di tipo T che notifica la funzione chiamante che nessun oggetto è stato trovato. Non voglio un'eccezione perché non è davvero una circostanza eccezionale.

Questo è ciò che il mio aspetto codice come in questo momento:

class Node {
    Attr& getAttribute(const string& attribute_name) const {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return NULL; // what should this be?
    }

private:
    vector<Attr> attributes;
}

Come posso cambiarlo in modo da posso dare questo tipo di marcatore?

È stato utile?

Soluzione

In C ++, i riferimenti non può essere nullo. Se si desidera tornare opzionalmente null se non viene trovato nulla, è necessario restituire un puntatore, non un riferimento:

Attr *getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return &attributes[i];
   //if not found
        return nullptr;
}

In caso contrario, se ti ostini a tornare per riferimento, allora si dovrebbe generare un'eccezione se l'attributo non viene trovato.

(A proposito, io sono un po 'preoccupato per il metodo di essere const e restituendo un attributo non const. Per ragioni filosofiche, suggerirei di tornare const Attr *. Se anche voi potrebbe voler modificare questo attributo, è possibile overload con un metodo non const restituendo un attributo non const pure.)

Altri suggerimenti

Ci sono diverse possibili risposte qui. Si vuole restituire qualcosa che potrebbe esistere. Qui ci sono alcune opzioni, che vanno dal mio almeno preferiva più preferito:

  • Rientro di riferimento, e il segnale può-non-trovare per eccezione.

    Attr& getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            throw no_such_attribute_error;
    }

E 'probabile che non trovando gli attributi è una parte normale di esecuzione, e quindi non del tutto eccezionali. Il trattamento per questo sarebbe rumoroso. Un valore nullo non può essere restituito perché è un comportamento indefinito di avere riferimenti nulli.

  • Rientro puntatore

    Attr* getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return &attributes[i];
       //if not found
            return nullptr;
    }

E 'facile dimenticare di controllare se un risultato da getAttribute sarebbe un puntatore non nullo, ed è una fonte facile di bug.

  • Boost.Optional

    boost::optional<Attr&> getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return boost::optional<Attr&>();
    }

una spinta :: opzionale significa esattamente che cosa sta succedendo qui, e ha metodi facili per il controllo se è stato trovato un tale attributo.


Nota a margine:. Std :: opzionale è stato recentemente votato in C ++ 17, quindi questo sarà una cosa "normale" in un prossimo futuro

È possibile creare facilmente un oggetto statico che rappresenta un ritorno NULL.

class Attr;
extern Attr AttrNull;

class Node { 
.... 

Attr& getAttribute(const string& attribute_name) const { 
   //search collection 
   //if found at i 
        return attributes[i]; 
   //if not found 
        return AttrNull; 
} 

bool IsNull(const Attr& test) const {
    return &test == &AttrNull;
}

 private: 
   vector<Attr> attributes; 
};

E da qualche parte in un file sorgente:

static Attr AttrNull;

Se si desidera un valore di ritorno NULL è necessario utilizzare puntatori invece di riferimenti.

I riferimenti non possono essere essi stessi NULL.

. (Nota per i futuri commento manifesti: Sì, è possibile avere l'indirizzo di un riferimento essere NULL se davvero davvero cercare di)

Vedere la mia risposta qui per una lista delle differenze tra riferimenti e puntatori .

Come avrete capito che non si può farlo nel modo che avete fatto in Java (o C #). Ecco un altro suggerimento, si potrebbe passare nel riferimento dell'oggetto come valore bool discussione e ritorno. Se il risultato è trovato nella vostra collezione, è possibile assegnare al riferimento essendo passati e ritorno ‘vero’, altrimenti restituisce ‘false’. Si prega di prendere in considerazione questo codice.

typedef std::map<string, Operator> OPERATORS_MAP;

bool OperatorList::tryGetOperator(string token, Operator& op)
{
    bool val = false;

    OPERATORS_MAP::iterator it = m_operators.find(token);
    if (it != m_operators.end())
    {
        op = it->second;
        val = true;
    }
    return val;
}

La funzione di cui sopra deve trovare l'Operatore contro il tasto 'token', se trova quella che restituisce true e assegnare il valore di parametro di Operatore e op.

Il codice chiamante per questo sembra di routine, come questo

Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
    //Do something here if true is returned.
}

Il motivo per cui non è possibile tornare NULL qui è perché hai dichiarato il tipo di ritorno come Attr&. Il & posteriore rende il valore restituito un "riferimento", che è fondamentalmente un garantito-non-essere-nullo puntatore a un oggetto esistente. Se si vuole essere in grado di restituire null, il cambiamento Attr& a Attr*.

Non si riesce a tornare NULL perché il tipo di ritorno della funzione è un reference oggetto e non un pointer.

Si può provare questo:

return &Type();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top