2017-07-30 1 views
2

Ceci est plus d'une question académique puisque je sais d'éviter généralement const_cast.Est-il possible d'utiliser const_cast sur un tableau pour changer des éléments?

Mais je travaillais sur l'exercice dans le chapitre 3, n ° 27 de la pensée en C++, vol. 1.

Créer un tableau const de double et un tableau de volatiles double. Indexez et utilisez const_cast pour convertir chaque élément en non-const et non-volatile, respectivement, et affecter une valeur à chaque élément .

Je vois comment const_cast vars unique:

const int i = 0; 
int* j = const_cast<int*>(&i); 

*j = 1; // compiles and runs 

mais ne peut pas comprendre comment le faire fonctionner avec un tableau. La compilation suivante, mais lève une exception «mauvais accès», comme si const est toujours là.

const int sz = 10; 
const double cd[sz] {0,1,2,3,4,5,6,7,8,9}; 
volatile double vd[sz] {0,1,2,3,4,5,6,7,8,9}; 

double* cdp = const_cast<double*>(cd); 
double* vdp = const_cast<double*>(vd); 

cdp[0] = 99; // bad access error 

Où est-ce que je me suis trompé?

+0

Vous ne pouvez pas modifier quelque chose qui est const. mentir au compilateur ne fait pas que travailler. – NathanOliver

+5

Vos deux exemples présentent un comportement indéfini. "Compile et exécute" est une manifestation possible d'un comportement indéfini; "erreur d'accès incorrect" en est une autre. Voir aussi: [démons nasaux] (http://www.catb.org/jargon/html/N/nasal-demons.html). Un livre qui suggère que c'est une bonne idée d'écrire du code présentant UB est, dirons-nous, pas un très bon livre pour étudier le C++. –

+0

'* j = 1; // compiles et runs' .. mais qu'est-ce que 'cout << i' et' cout << * j' impriment? – txtechhelp

Répondre

2

S'il vous plaît noter:

const int i = 0; 
int* j = const_cast<int*>(&i); 

*j = 1; // UNDEFINED BEHAVIOR - modify actually const data 

Vous êtes pas autorisé à modifier un objet par coulée constness qui a été loin d'abord déclaré const. Le compilateur peut placer le contenu de l'objet (ou du tableau, dans votre cas) dans une mémoire en lecture seule qui est appliquée à un niveau inférieur dans la machine au compilateur. Lorsque vous écrivez, cela peut déclencher une erreur. Si elle est déclarée const, vous devez l'honorer pour toujours, ou recevoir des plantages pendant que vous vivez.

C'est seulement ok pour modifier après avoir ignoré la constance si l'objet a été initialement déclaré non-const. (Autrement dit, la constance a été ajoutée plus tard, peut-être en tant que paramètre de référence à une fonction.)

Reformulons votre question dans au moins une situation valide à titre d'exemple.

// f() takes a reference to an array, but add constness 
void f(const double(&arr)[10]) 
{ 
    // Here it's ok to cast away constness and modify since the 
    // underlying object isn't declared const (though in general a 
    // function doesn't know that about its caller, except in 
    // constrained situations.) 
    double * array = const_cast<double*>(arr); 
    array[1] = 99; 
} 

int main() 
{ 
    // NOTE: array is NOT CONST 
    double arr[10] {0,1,2,3,4,5,6,7,8,9}; 
    f(arr); 
} 

Et c'est bien.

+0

OK.Merci de m'avoir montré un cas d'utilisation viable. – bigswifty

+1

Ceci est incorrect. Il est parfaitement possible de rejeter la constance de tout pointeur de const que vous avez, indépendamment de ce que ce pointeur indique. Votre raisonnement ne s'applique pas; les restrictions matérielles n'entrent pas en jeu avec de telles opérations. C'est seulement UB à _modify_ un objet const, avec l'exception subobjects mutable. IOW, la ligne que vous avez marquée comme UB est en fait parfaitement bien; la ligne suivante, '* j = 1;', est UB. –

+0

Merci @HWalters, j'ai serré les boulons en réponse à votre demande. :) –