153 votes

C ++: référence nulle

Est ce morceau de code valide (et de comportement défini)?

int &nullReference = *(int*)0;

Les deux g++ et clang++ compiler sans aucun avertissement, même lors de l'utilisation d' -Wall, -Wextra, -std=c++98, -pedantic, -Weffc++...

Bien sûr, la référence n'est pas réellement nulle, car elle ne sera pas accessible (ça voudrait dire déréférencement d'un pointeur null), mais nous n'avons pu vérifier si elle est null ou non par la vérification de son adresse:

if( & nullReference == 0 ) // null reference

97voto

Steve Jessop Points 166970

Les références ne sont pas des pointeurs.

8.3.2/1:

Une référence doit être initialisée à se référer à un objet valide ou d'une fonction. [Note: en particulier, une référence null ne peut pas exister dans des conditions bien définies programme, parce que la seule façon de créer une telle référence serait de lier à la "objet" obtenues par l' un déréférencement d'un pointeur null, ce qui provoque un comportement indéfini. Comme décrit dans 9.6, une référence ne peut pas être lié directement à un peu de champ. ]

1.9/4:

Certaines autres opérations sont décrites dans la présente Norme Internationale comme non défini (par exemple, l'effet de un déréférencement du pointeur null)

Comme Johannes dit supprimé réponse, il y a un doute à savoir si le "déréférencement d'un pointeur null" doit être déclaré catégoriquement à un comportement indéfini. Mais ce n'est pas l'un des cas qui soulèvent des doutes, puisqu'un pointeur null n'est certainement pas un "objet valide ou d'une fonction", et il n'y a pas de désir au sein du comité des normes d'introduire des références nulles.

9voto

David Lee Points 121

Si votre intention était de trouver un moyen de représenter null dans une énumération d'objets singleton, c'est une mauvaise idée de (dé) référencer null (le C ++ 11, nullptr).

Pourquoi ne pas déclarer un objet singleton statique qui représente NULL dans la classe comme suit et ajouter un opérateur cast-to-pointeur qui retourne nullptr?

 // Error.h
class Error {
public:
  static Error& NOT_FOUND;
  static Error& UNKNOWN;
  static Error& NONE; // singleton object that represents null

public:
  static vector<shared_ptr<Error>> _instances;
  static Error& NewInstance(const string& name, bool isNull = false);

private:
  bool _isNull;
  Error(const string& name, bool isNull = false) : _name(name), _isNull(isNull) {};
  Error() {};
  Error(const Error& src) {};
  Error& operator=(const Error& src) {};

public:
  operator Error*() { return _isNull ? nullptr : this; }
};

// Error.cpp
vector<shared_ptr<Error>> Error::_instances;
Error& Error::NewInstance(const string& name, bool isNull = false)
{
  shared_ptr<Error> pNewInst(new Error(name, isNull)).
  Error::_instances.push_back(pNewInst);
  return *pNewInst.get();
}

Error& Error::NOT_FOUND = Error::NewInstance("NOT_FOUND");
Error& Error::NOT_FOUND = Error::NewInstance("UNKNOWN");
Error& Error::NOT_FOUND = Error::NewInstance("NONE", true);

// Main.cpp
#include "Error.h"

Error& getError() {
  return Error::UNKNOWN;
}

int main(void) {
  if(getError() != Error::NONE) {
    return EXIT_FAILURE;
  }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X