web-dev-qa-db-fra.com

Renvoie un objet "NULL" si le résultat de la recherche est introuvable

Comme je suis assez nouveau en C++, j'ai tendance à concevoir avec beaucoup de Java-isms pendant que j'apprends. Quoi qu'il en soit, en Java, si j'avais une classe avec une méthode 'search' qui retournerait un objet T à partir d'un Collection< T > Qui correspondait à un paramètre spécifique, je retournerais cet objet et si l'objet était non trouvé dans la collection, je retournerais null. Ensuite, dans ma fonction d'appel, je vérifierais simplement if(tResult != null) { ... }

En C++, je découvre que je ne peux pas retourner de valeur null si l'objet n'existe pas. Je veux juste renvoyer un "indicateur" de type T qui indique à la fonction appelante qu'aucun objet n'a été trouvé. Je ne veux pas faire d'exception car ce n'est pas vraiment une circonstance exceptionnelle.

Voici à quoi ressemble mon code:

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;
}

Comment puis-je le changer afin que je puisse donner ce type de marqueur?

90
aduric

En C++, les références ne peuvent pas être nulles. Si vous souhaitez éventuellement renvoyer null si rien n'est trouvé, vous devez renvoyer un pointeur, pas une référence:

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

Sinon, si vous insistez pour retourner par référence, vous devriez alors lever une exception si l'attribut n'est pas trouvé.

(Au fait, je crains un peu que votre méthode soit const et renvoie un attribut non -const. Pour des raisons philosophiques, je suggérerais de renvoyer const Attr *. Si vous souhaitez également modifier cet attribut, vous pouvez surcharger avec une méthode non -const renvoyant également un attribut non -const.)

65
Jesse Beder

Il y a plusieurs réponses possibles ici. Vous voulez retourner quelque chose qui pourrait exister. Voici quelques options, allant du moins préféré au plus préféré:

  • Retour par référence et signal impossible à trouver par exception.

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

Il est probable que le fait de ne pas trouver d'attributs fasse partie de l'exécution normale et n'est donc pas très exceptionnel. La manipulation de ce serait bruyant. Une valeur NULL ne peut pas être renvoyée car son comportement non défini consiste à avoir des références NULL.

  • Retour par pointeur

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

Il est facile d'oublier de vérifier si le résultat de getAttribute serait un pointeur non NULL et constituerait une source facile de bogues.

  • Utilisez 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&>();
    }

Un boost :: optional signifie exactement ce qui se passe ici et propose des méthodes simples pour vérifier si un tel attribut a été trouvé.


Note latérale: std :: optional a récemment été voté en C++ 17, ce sera donc une chose "standard" dans un avenir proche.

55
Kaz Dragon

Vous pouvez facilement créer un objet statique qui représente un retour 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; 
};

Et quelque part dans un fichier source:

static Attr AttrNull;
22
Mark Ransom

Si vous voulez une valeur de retour NULL, vous devez utiliser des pointeurs au lieu de références.

Les références ne peuvent pas être elles-mêmes NULL.

(Remarque pour les futures affiches de commentaires: Oui, vous pouvez indiquer l'adresse d'une référence si la valeur est NULL si vous essayez vraiment de le faire).

Voir ma réponse ici pour une liste des différences entre les références et les pointeurs .

3
Brian R. Bondy

Comme vous l'avez compris, vous ne pouvez pas le faire comme vous l'avez fait avec Java (ou C #). Voici une autre suggestion. Vous pouvez transmettre la référence de l'objet sous forme d'argument et la renvoyer. Valeur booléenne. Si le résultat est trouvé dans votre collection, vous pouvez l'affecter à la référence passée et renvoyer 'true', sinon, 'false'. Veuillez considérer ce code.

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 fonction ci-dessus doit rechercher l'opérateur contre la clé 'token', si elle trouve celle qu'il renvoie, et attribuer la valeur au paramètre Operator & op.

Le code de l'appelant pour cette routine ressemble à ceci

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

La raison pour laquelle vous ne pouvez pas renvoyer NULL ici est que vous avez déclaré votre type de retour comme Attr&. La fuite & fait de la valeur de retour une "référence", qui est fondamentalement un pointeur sur-un-objet-garanti. Si vous voulez pouvoir retourner null, changez Attr& à Attr*.

1
JSBձոգչ

Vous ne pouvez pas renvoyer NULL car le type de retour de la fonction est un objet reference et non un pointer.

0
codaddict