Quelqu'un peut-il expliquer pourquoi les pointeurs ne sont pas initialisés NULL
?
Exemple:
void test(){
char *buf;
if (!buf)
// whatever
}
Le programme n'entrerait pas dans le if car il buf
n'est pas nul.
Je voudrais savoir pourquoi, dans quel cas avons-nous besoin d'une variable avec corbeille, spécialement des pointeurs adressant la corbeille sur la mémoire?
c++
memory
pointers
initialization
Jonathan
la source
la source
Réponses:
Nous savons tous que le pointeur (et les autres types de POD) doivent être initialisés.
La question devient alors «qui doit les initialiser».
Eh bien, il existe essentiellement deux méthodes:
Supposons que le compilateur ait initialisé toute variable non explicitement initialisée par le développeur. Ensuite, nous nous heurtons à des situations où l'initialisation de la variable n'était pas triviale et la raison pour laquelle le développeur ne l'a pas fait au point de déclaration était qu'il / elle avait besoin d'effectuer une opération puis de l'assigner.
Nous avons donc maintenant la situation dans laquelle le compilateur a ajouté une instruction supplémentaire au code qui initialise la variable à NULL, puis plus tard, le code du développeur est ajouté pour effectuer l'initialisation correcte. Ou dans d'autres conditions, la variable n'est potentiellement jamais utilisée. Beaucoup de développeurs C ++ hurleraient dans les deux conditions au prix de cette instruction supplémentaire.
Ce n'est pas seulement une question de temps. Mais aussi de l'espace. Il y a beaucoup d'environnements où les deux ressources sont à une prime et les développeurs ne veulent pas abandonner non plus.
MAIS : vous pouvez simuler l'effet de forcer l'initialisation. La plupart des compilateurs vous avertiront des variables non initialisées. Je tourne donc toujours mon niveau d'avertissement au niveau le plus élevé possible. Dites ensuite au compilateur de traiter tous les avertissements comme des erreurs. Dans ces conditions, la plupart des compilateurs généreront alors une erreur pour les variables non initialisées mais utilisées et empêcheront ainsi la génération de code.
la source
Citant Bjarne Stroustrup dans TC ++ PL (Special Edition p.22):
la source
D
fait. Si vous ne souhaitez pas l'initialisation, utilisez cette syntaxefloat f = void;
ouint* ptr = void;
. Maintenant, il est initialisé par défaut, mais si vous en avez vraiment besoin, vous pouvez empêcher le compilateur de le faire.Parce que l'initialisation prend du temps. Et en C ++, la toute première chose à faire avec n'importe quelle variable est de l'initialiser explicitement:
ou:
ou:
la source
Parce que l'une des devises de C ++ est:
Vous ne payez pas pour ce que vous n'utilisez pas
Pour cette raison, le
operator[]
de lavector
classe ne vérifie pas si l'index est hors limites, par exemple.la source
Pour des raisons historiques, principalement parce que c'est ainsi que cela se fait en C. Pourquoi cela se fait comme cela en C, est une autre question, mais je pense que le principe de zéro frais généraux a été impliqué d'une manière ou d'une autre dans cette décision de conception.
la source
De plus, nous avons un avertissement pour le moment où vous le faites exploser: "est peut-être utilisé avant d'attribuer une valeur" ou un verbage similaire en fonction de votre compilateur.
Vous compilez avec des avertissements, non?
la source
Il existe très peu de situations dans lesquelles il est logique qu'une variable ne soit pas initialisée, et l'initialisation par défaut a un petit coût, alors pourquoi le faire?
C ++ n'est pas C89. Bon sang, même C n'est pas C89. Vous pouvez mélanger les déclarations et le code, vous devez donc différer la déclaration jusqu'à ce que vous ayez une valeur appropriée pour l'initialisation.
la source
Un pointeur est juste un autre type. Si vous créez un
int
,char
ou tout autre type POD il n'est pas initialisés à zéro, alors pourquoi un pointeur? Cela pourrait être considéré comme une surcharge inutile pour quelqu'un qui écrit un programme comme celui-ci.Si vous savez que vous allez l'initialiser, pourquoi le programme devrait-il engager un coût lorsque vous créez
pBuf
pour la première fois en haut de la méthode? C'est le principe de zéro frais généraux.la source
Si vous voulez un pointeur qui est toujours initialisé à NULL, vous pouvez utiliser un modèle C ++ pour émuler cette fonctionnalité:
la source
Foo *a
, vous utilisezInitializedPointer<Foo> a
- Un exercice purement académique carFoo *a=0
c'est moins de frappe. Cependant, le code ci-dessus est très utile d'un point de vue pédagogique. Avec une petite modification (au ctor / dtor "placeholding" et aux opérations d'assignation), il pourrait être facilement étendu à divers types de pointeurs intelligents, y compris les pointeurs de portée (qui sont gratuits sur le destructeur) et les pointeurs comptés par référence en ajoutant inc / dec opérations lorsque le m_pPointer est défini ou effacé.Notez que les données statiques sont initialisées à 0 (sauf indication contraire).
Et oui, vous devez toujours déclarer vos variables le plus tard possible et avec une valeur initiale. Code comme
devrait déclencher l'alarme lorsque vous le lisez. Je ne sais pas si des peluches peuvent être persuadées de s'en plaindre car c'est 100% légal.
la source
Une autre raison possible est qu'au moment de la liaison, les pointeurs reçoivent une adresse, mais l'adressage indirect / le dé-référencement d'un pointeur est la responsabilité du programmeur. Généralement, le compilateur s'en fiche, mais le fardeau est transféré au programmeur pour gérer les pointeurs et s'assurer qu'aucune fuite de mémoire ne se produit.
En fait, en un mot, ils sont initialisés en ce sens qu'au moment de la liaison, la variable pointeur reçoit une adresse. Dans votre exemple de code ci-dessus, cela est garanti pour planter ou générer un SIGSEGV.
Pour des raisons de bon sens, initialisez toujours les pointeurs à NULL, de cette manière si une tentative de déréférencer sans
malloc
ounew
indiquera au programmeur la raison pour laquelle le programme s'est mal comporté.J'espère que cela aide et a du sens,
la source
Eh bien, si C ++ initialisait les pointeurs, alors les gens du C se plaignant de "C ++ est plus lent que C" auraient quelque chose de réel auquel s'accrocher;)
la source
C ++ vient d'un arrière-plan C - et il y a plusieurs raisons qui en découlent:
C, encore plus que C ++, est un remplacement du langage assembleur. Il ne fait rien que vous ne lui dites pas de faire. Par conséquent: si vous voulez le NULL, faites-le!
De plus, si vous annulez des choses dans un langage bare-metal comme C, des questions de cohérence surgissent automatiquement: si vous malloc quelque chose - devrait-il être automatiquement remis à zéro? Qu'en est-il d'une structure créée sur la pile? tous les octets doivent-ils être remis à zéro? Qu'en est-il des variables globales? qu'en est-il d'une déclaration comme "(* 0x18);" cela ne signifie-t-il pas alors que la position de mémoire 0x18 doit être remise à zéro?
la source
calloc()
.De quoi parlez-vous?
Pour plus de sécurité d'exception, utilisez toujours
auto_ptr
,shared_ptr
,weak_ptr
et leurs autres variantes.Une caractéristique d'un bon code est celle qui n'inclut pas un seul appel
delete
.la source
auto_ptr
et remplacezunique_ptr
.Oh mec. La vraie réponse est qu'il est facile de mettre à zéro la mémoire, ce qui est une initialisation de base pour, par exemple, un pointeur. Ce qui n'a rien à voir avec l'initialisation de l'objet lui-même.
Compte tenu des avertissements que la plupart des compilateurs donnent aux niveaux les plus élevés, je ne peux pas imaginer programmer au plus haut niveau et les traiter comme des erreurs. Depuis leur mise en place ne m'a jamais sauvé même un bogue dans d'énormes quantités de code produites, je ne peux pas le recommander.
la source
NULL
, son initialisation est tout autant une erreur.