220 lines
7.7 KiB
Plaintext
220 lines
7.7 KiB
Plaintext
[set
|
||
title = "La valeur [c null] et l'Opérateur [c is]"
|
||
partAs = chapitre
|
||
translator = "Raphaël Jakse"
|
||
proofreader = "Stéphane Goujet"
|
||
]
|
||
|
||
Dans le chapitre précédent, nous avons vu qu'une variable d'un type référence n'a pas besoin de référencer un objet :
|
||
|
||
[code=d <<<
|
||
MaClasse referenceUnObjet = new MaClasse;
|
||
MaClasse variable; // ne référence pas un objet
|
||
>>>]
|
||
|
||
Étant d'un type par référence, [c variable] a, dans le code précédent, une identité mais ne référence pas encore d'objet. Un tel objet peut être représenté comme ceci dans sa case mémoire~ :
|
||
|
||
[pre <<<
|
||
variable
|
||
---+------+---
|
||
| null |
|
||
---+------+---
|
||
>>>]
|
||
|
||
Une référence qui ne référence aucune valeur est [c null]. Nous développerons ce point.
|
||
|
||
Une telle variable est dans un état quasiment inutile. Comme elle ne référence pas d'objet, elle ne peut pas être utilisée dans un contexte où un objet [c MaClasse] est requis~ :
|
||
|
||
|
||
[code=d <<<
|
||
import std.stdio;
|
||
|
||
class MaClasse
|
||
{
|
||
int membre;
|
||
}
|
||
|
||
void utiliser(MaClasse variable)
|
||
{
|
||
writeln(variable.membre); // ← BOGUE
|
||
}
|
||
|
||
void main()
|
||
{
|
||
MaClasse variable;
|
||
utiliser(variable);
|
||
}
|
||
>>>]
|
||
|
||
Il n'y a pas d'objet référencé par le paramètre que la fonction [c utiliser] reçoit. Essayer d'accéder à un membre d'un objet non existant fait planter le programme~ :
|
||
|
||
[code <<<
|
||
$ ./essai
|
||
$ Erreur de segmentation
|
||
>>>]
|
||
|
||
«~ Erreur de segmentation~ » est une indication que le programme a été tué par le système d'exploitation parce qu'il a essayé d'accéder à une adresse mémoire illégale.
|
||
|
||
[ = La valeur [c null]
|
||
|
||
La valeur spéciale [c null] peut être affichée comme n'importe quelle autre valeur.
|
||
|
||
[code=d <<<
|
||
writeln(null); // affiche 'null' dans la sortie
|
||
>>>]
|
||
|
||
Comme dans beaucoup d'autres langages, la représentation entière de [c null] est 0.
|
||
|
||
Une variable [c null] peut être utilisée dans deux contextes~ :
|
||
# [
|
||
En lui affectant un objet
|
||
[code=d <<<
|
||
variable = new MaClasse; // référence maintenant un objet
|
||
>>>]
|
||
|
||
Cette affectation fait pointer [c variable] vers l'objet nouvellement créé. À partir de là, [c variable] peut être utilisée pour n'importe quelle opération valide du type [c MaClasse].
|
||
|
||
]
|
||
# [
|
||
Pour déterminer si elle est [c null].
|
||
|
||
Cependant, comme l'opérateur [c ==] a besoin de deux objets pour faire la comparaison, l'expression qui suit ne peut pas être compilée~ :
|
||
|
||
[code=d <<<
|
||
if (variable == null) // ERREUR de compilation
|
||
>>>]
|
||
|
||
Pour cette raison, pour savoir si une variable est [c null], on utilise l'opérateur [c is].
|
||
|
||
|
||
]
|
||
]
|
||
[ = L'opérateur [c is]
|
||
|
||
Cet opérateur répond à la question "a la valeur nulle ?" (NdT : ''is'' veut dire «~ est~ » en anglais)~ :
|
||
|
||
[code=d <<<
|
||
if (variable is null) {
|
||
// Ne référence aucun objet
|
||
}
|
||
>>>]
|
||
|
||
L'opérateur [c is] peut aussi être utilisé avec d'autres types de variable. Dans l'utilisation suivante, il compare les valeurs de deux entiers~ :
|
||
|
||
[code=d <<<
|
||
if (vitesse is nouvelleVitesse) {
|
||
// Leurs valeurs sont égales
|
||
|
||
} else {
|
||
// Leurs valeurs sont différentes
|
||
}
|
||
>>>]
|
||
|
||
Lorsqu'on l'utilise avec les tranches, il détermine si deux tranches référencent le même ensemble d'éléments~ :
|
||
|
||
[code=d <<<
|
||
if (tranche is tranche2) {
|
||
// Elles donnent accès aux mêmes éléments
|
||
}
|
||
>>>]
|
||
|
||
]
|
||
[ = L'opérateur [c !is]
|
||
[c !is] est l'opposé de [c is]. Il donne [c true] quand les valeurs sont différentes~ :
|
||
|
||
[code=d <<<
|
||
if (vitesse !is nouvelleVitesse) {
|
||
// Leurs valeurs sont différentes
|
||
}
|
||
>>>]
|
||
]
|
||
|
||
[ = Affecter la valeur [c null]
|
||
|
||
Affecter la valeur [c null] à une variable de type référence fait que la variable arrête de référencer son objet actuel.
|
||
|
||
S'il se trouve que cette affectation supprime la dernière référence à cet objet, alors l'objet devient un candidat à la finalisation par le ramasse-miette. En effet, pour un objet, n'être référencé par aucune variable veut dire qu'il n'est pas utilisé du tout dans le programme.
|
||
|
||
Regardons l'exemple d'[[part:valeur_vs_reference |un chapitre précédent] où deux variables référençaient le même objet~ :
|
||
|
||
[code=d <<<
|
||
auto variable = new MaClasse;
|
||
auto variable2 = variable;
|
||
>>>]
|
||
|
||
Ce qui suit est une représentation de l'état de la mémoire après l'exécution de ce code~ :
|
||
|
||
[pre <<<
|
||
(objet MaClasse anonyme) variable variable2
|
||
---+-------------------+--- ---+---+--- ---+---+---
|
||
| ... | | o | | o |
|
||
---+-------------------+--- ---+-|-+--- ---+-|-+---
|
||
▲ | |
|
||
| | |
|
||
+--------------------+------------+
|
||
>>>]
|
||
|
||
Affecter la valeur [c null] à l'une des deux variables casse sa relation avec l'objet~ :
|
||
|
||
|
||
[code=d <<<
|
||
variable = null;
|
||
>>>]
|
||
|
||
À partir de ce point, il n'y a plus que [c variable2] qui référence l'objet~ :
|
||
|
||
|
||
[pre <<<
|
||
(objet MaClasse anonyme) variable variable2
|
||
---+-------------------+--- ---+------+--- ---+---+---
|
||
| ... | | null | | o |
|
||
---+-------------------+--- ---+------+--- ---+-|-+---
|
||
▲ |
|
||
| |
|
||
+------------------------------------+
|
||
>>>]
|
||
|
||
Affecter [c null] à la dernière référence rendrait l'objet inatteignable~ :
|
||
|
||
[code=d <<<
|
||
variable2 = null;
|
||
>>>]
|
||
|
||
Un tel objet inatteignable sera finalisé par le ramasse-miette à un certain moment dans le futur. Du point de vue du programme, l'objet n'existe pas~ :
|
||
|
||
|
||
[pre <<<
|
||
variable variable2
|
||
---+-------------------+--- ---+------+--- ---+------+---
|
||
| | | null | | null |
|
||
---+-------------------+--- ---+------+--- ---+------+---
|
||
>>>]
|
||
|
||
Nous avons discuté des moyens de vider un tableau associatif dans les exercices du [[part:tableaux_associatifs | chapitre sur les tableaux associatifs]. Nous connaissons maintenant une quatrième méthode~ : affecter [c null] à un tableau associatif casse la relation entre cette variable et les éléments~ :
|
||
|
||
[code=d <<<
|
||
string[int] noms;
|
||
// ...
|
||
noms = null; // Ne donne accès à aucun élément
|
||
>>>]
|
||
|
||
De manière similaire aux exemples avec [c MaClasse], si [c noms] était la dernière référence aux éléments du tableau associatif, ces éléments seront finalisés par le ramasse-miette.
|
||
|
||
Les tranches peuvent également être affectées à [c null]~ :
|
||
|
||
[code=d <<<
|
||
int[] tranche = autreTranche[ 10 .. 20 ];
|
||
// ...
|
||
tranche = null; // Ne donne accès à aucun élément
|
||
>>>]
|
||
]
|
||
|
||
[ = Résumé
|
||
- [c null] est la valeur indiquant qu'une variable ne donne accès à aucun élément.
|
||
- Les références qui ont la valeur [c null] ne peuvent être utilisées que dans deux opérations~ : leur affecter une valeur et déterminer si elle sont [c null] ou pas.
|
||
- Comme l'opérateur [c ==] peut nécessiter l'accès à un objet, déterminer si une variable est [c null] doit être fait avec l'opérateur [c is].
|
||
- [c !is] est l'opposé de [c is].
|
||
- Affecter [c null] à une variable fait que cette variable ne pointe plus vers aucun objet.
|
||
- Les objets qui ne sont référencés par aucune variable sont finalisés par le ramasse-miette.
|
||
]
|