7 votes

Référence à une mémoire non initialisée. Comportement indéfini ?

Permettez-moi de dire en préambule que je ne recommande aucune des pratiques ci-dessous, pour des raisons évidentes. Cependant, j'ai eu une discussion aujourd'hui à ce sujet et certaines personnes étaient catégoriques sur le fait que l'utilisation d'une référence comme celle-ci constituait un comportement indéfini.

Voici un cas d'essai :

#include <string>

struct my_object {
   int a          = 1;
   int b          = 2;
   std::string hi = "hello";
};

// Using union purely to reserve uninitialized memory for a class.
union my_object_storage {
   char dummy;
   my_object memory;
   // C++ will yell at you for doing this without some constructors.
   my_object_storage() {}
   ~my_object_storage() {}
} my_object_storage_instance;

// This is so we can easily access the storage memory through "I"
constexpr my_object &I = my_object_storage_instance.memory;

//-------------------------------------------------------------
int main() {
   // Initialize the object.
   new (&I) my_object();
   // Use the reference.
   I.a = 1;
   // Destroy the object (typically this should be done using RAII).
   I.~my_object();

   // Phase two, REINITIALIZE an object with the SAME reference.
   // We still have the memory allocated which is static, so why not?
   new (&I) my_object();
   // Use the reference.
   I.a = 1;  
   // Destroy the object again. 
   I.~my_object();
}

https://wandbox.org/permlink/YEp9aQUcWdA9YiBI

En gros, ce que fait le code est de réserver de la mémoire statique pour une structure, puis de l'initialiser dans main(). Pourquoi voudriez-vous faire cela ? Ce n'est pas extrêmement utile et vous devriez simplement utiliser un pointeur, mais voici la question :

Avec cette déclaration donnée,

constexpr my_object &I = my_object_storage_instance.memory;

La définition d'une référence à une mémoire non initialisée est-elle un comportement non défini ? D'autres personnes m'ont dit que oui, mais j'essaie de savoir concrètement si c'est le cas. Dans la norme C++, nous voyons ce paragraphe :

Une référence doit être initialisée pour faire référence à un objet ou une fonction valide. [Note : en particulier, une référence nulle ne peut pas exister dans un programme bien défini, car la seule façon de créer une telle référence serait de la lier à l'"objet" obtenu par déréférencement d'un pointeur nul, ce qui provoque un comportement indéfini.

Plus précisément "un objet valide" La question qui se pose est la suivante : un objet dont le constructeur n'a pas encore été appelé est-il "valide" ? Qu'est-ce qui le rend invalide au point de provoquer un comportement indéfini ? Y a-t-il des effets secondaires réels qui pourraient survenir ?

Mon argument pour ce qui est étiqueté comme un comportement indéfini :

  • Compilateurs pourrait être libre de le traiter comme un objet valide, car la norme stipule qu'il doit l'être, surtout pendant l'affectation et surtout si des instructions de débogage cachées sont insérées pour des diagnostics qui le supposent, ce qui provoquerait certainement un comportement indéfini.

Mes arguments contre c'est que le comportement est indéfini :

  • Il ne déréférence rien du tout - le paragraphe stipule que, pendant l'initialisation d'une référence, le déréférencement nullptr est indéfini. Elle n'indique pas spécifiquement un comportement indéfini s'il n'y a pas de déréférencement.
  • Les références flottantes sont une chose, et apparaissent dans de nombreux cas dans les programmes normaux. Elles ne provoquent un comportement indéfini que SI elles sont utilisées. Ceci est similaire au fait de commencer avec une référence pendante.

Encore une fois, ce n'est pas très utile en pratique parce qu'il y a de bien meilleures façons de passer son temps, mais quel meilleur endroit que stackoverflow pour les questions bizarres et les avis d'experts ? :)

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