web-dev-qa-db-fra.com

Recherche d'un objet nul en C ++

Je n'ai principalement travaillé qu'avec C et je rencontre des problèmes inconnus en C++.

Disons que j'ai une fonction comme celle-ci en C, ce qui serait très typique:

int some_c_function(const char* var)
{
    if (var == NULL) {
        /* Exit early so we don't dereference a null pointer */
    }
    /* The rest of the code */
}

Et disons que j'essaie d'écrire une fonction similaire en C++:

int some_cpp_function(const some_object& str)
{
    if (str == NULL)  // This doesn't compile, probably because some_object doesn't overload the == operator

    if (&str == NULL) // This compiles, but it doesn't work, and does this even mean anything?
}

Fondamentalement, tout ce que j'essaie de faire est d'empêcher le programme de planter lorsque some_cpp_function () est appelé avec NULL.

  • Quelle est la façon la plus courante/courante de le faire avec un objet C++ (qui n'implique pas de surcharger le == opérateur)?

  • Est-ce même la bonne approche? Autrement dit, ne devrais-je pas écrire des fonctions qui prennent un objet en argument, mais plutôt des fonctions membres? (mais même si c'est le cas, veuillez répondre à la question d'origine)

  • Entre une fonction qui prend une référence à un objet ou une fonction qui prend un pointeur de style C vers un objet, y a-t-il des raisons de choisir l'une plutôt que l'autre?

32
bcx_2000

Fondamentalement, tout ce que j'essaie de faire est d'empêcher le programme de planter lorsque some_cpp_function () est appelé avec NULL.

Il n'est pas possible d'appeler la fonction avec NULL. L'un des objectifs de la référence est qu'elle pointera toujours sur un objet car vous devez l'initialiser lors de sa définition. Ne pensez pas que la référence est un pointeur sophistiqué, pensez-y comme un nom d'alias pour l'objet lui-même. Ensuite, ce type de confusion ne se produira pas.

34
Naveen

Une référence ne peut pas être NULL. L'interface vous fait passer un véritable objet dans la fonction.

Il n'est donc pas nécessaire de tester NULL. C'est l'une des raisons pour lesquelles les références ont été introduites dans C++.

Notez que vous pouvez toujours écrire une fonction qui prend un pointeur. Dans cette situation, vous devez toujours tester NULL. Si la valeur est NULL, vous retournez tôt, tout comme en C. Remarque: vous ne devez pas utiliser d'exceptions lorsqu'un pointeur est NULL. Si un paramètre ne doit jamais être NULL, vous créez une interface qui utilise une référence.

14
Martin York

Comme tout le monde l'a dit, les références ne peuvent pas être nulles. En effet, une référence fait référence à un objet. Dans votre code:

// this compiles, but doesn't work, and does this even mean anything?
if (&str == NULL)

vous prenez l'adresse de l'objet str. Par définition, str existe, il a donc une adresse. Il ne peut donc pas s'agir de NULL. Donc, syntaxiquement, ce qui précède est correct, mais logiquement, la condition if va toujours être fausse.

A propos de vos questions: cela dépend de ce que vous voulez faire. Voulez-vous que la fonction puisse modifier l'argument? Si oui, passez une référence. Sinon, ne le faites pas (ou passez la référence à const). Voir cette FAQ C++ pour quelques bons détails.

En général, en C++, le passage par référence est préféré par la plupart des gens plutôt que le passage d'un pointeur. Une des raisons est exactement ce que vous avez découvert: une référence ne peut pas être NULL, vous évitant ainsi le mal de tête de la vérifier dans la fonction.

6
Alok Singhal

Une référence C++ n'est pas un pointeur ni une référence de style Java/C # et ne peut pas être NULL. Ils se comportent comme s'ils étaient un alias vers un autre objet existant.

Dans certains cas, s'il y a des bogues dans votre code, vous pouvez obtenir une référence dans un objet déjà mort ou inexistant, mais la meilleure chose que vous puissiez faire est d'espérer que le programme meurt assez tôt pour pouvoir déboguer ce qui s'est passé et pourquoi votre programme a été corrompu.

Autrement dit, j'ai vu du code vérifier les "références nulles" en faisant quelque chose comme: if ( &reference == 0 ), mais la norme est claire qu'il ne peut pas y avoir de références nulles dans un programme bien formé. Si une référence est liée à un objet nul, le programme est mal formé et doit être corrigé. Si vous avez besoin de valeurs facultatives, utilisez des pointeurs (ou une construction de niveau supérieur comme boost::optional), pas des références.

Vous pouvez utiliser un objet désigné spécial comme objet nul en cas de références comme suit:

class SomeClass
{
    public:

        int operator==(SomeClass &object)
        {
            if(this == &object) 
            {
                    return true;
            }

            return false;
        }


    static SomeClass NullObject;
};

SomeClass SomeClass::NullObject;

void print(SomeClass &val)
{
    if(val == SomeClass::NullObject)
    {
        printf("\nNULL");
    }
    else
    {
        printf("\nNOT NULL");
    }
}
4
Nilesh Pawar
  • Quelle est la façon la plus courante/courante de le faire avec un objet C++ (qui n'implique pas de surcharger l'opérateur ==)?
  • Est-ce même la bonne approche? c'est à dire. ne devrais-je pas écrire des fonctions qui prennent un objet en argument, mais plutôt des fonctions membres? (Mais même si c'est le cas, veuillez répondre à la question d'origine.)

Non, les références ne peuvent pas être nulles (sauf si un comportement indéfini s'est déjà produit, auquel cas tous les paris sont déjà désactivés). Que vous deviez écrire une méthode ou une non-méthode dépend d'autres facteurs.

  • Entre une fonction qui prend une référence à un objet ou une fonction qui prend un pointeur de style C vers un objet, y a-t-il des raisons de choisir l'une plutôt que l'autre?

Si vous devez représenter "aucun objet", passez un pointeur à la fonction et laissez ce pointeur NULL:

int silly_sum(int const* pa=0, int const* pb=0, int const* pc=0) {
  /* Take up to three ints and return the sum of any supplied values.

  Pass null pointers for "not supplied".

  This is NOT an example of good code.
  */
  if (!pa && (pb || pc)) return silly_sum(pb, pc);
  if (!pb && pc) return silly_sum(pa, pc);
  if (pc) return silly_sum(pa, pb) + *pc;
  if (pa && pb) return *pa + *pb;
  if (pa) return *pa;
  if (pb) return *pb;
  return 0;
}

int main() {
  int a = 1, b = 2, c = 3;
  cout << silly_sum(&a, &b, &c) << '\n';
  cout << silly_sum(&a, &b) << '\n';
  cout << silly_sum(&a) << '\n';
  cout << silly_sum(0, &b, &c) << '\n';
  cout << silly_sum(&a, 0, &c) << '\n';
  cout << silly_sum(0, 0, &c) << '\n';
  return 0;
}

Si "aucun objet" n'a jamais besoin d'être représenté, les références fonctionnent correctement. En fait, les surcharges des opérateurs sont beaucoup plus simples car elles prennent des surcharges.

Vous pouvez utiliser quelque chose comme boost :: facultatif.

2
Roger Pate

Vous devez utiliser NULL uniquement avec des pointeurs. Votre fonction accepte une référence et elle ne peut pas être NULL.

Écrivez votre fonction comme vous l'écririez en C.

2
Nikola Smiljanić

Les références C++ ne peuvent naturellement pas être nulles, vous n'avez pas besoin de la vérification. La fonction ne peut être appelée qu'en passant une référence à un objet existant.

2
sharptooth