2010-12-05 3 views
1

Je voudrais utiliser la même variable mais je souhaite la réinstituer. Comment puis-je le faire en C++? Voici un exemple simple. J'essaie de rétablir t1 mais il ne compile pas. (Avis t1 est stocké dans la pile. Je ne demande pas comment faire l'allocation dynamique de la mémoire)Réactivation de l'objet Stack en C++

class Table 
{ 
    private int feet; 
    public Table(int x) 
    { 
    feet=x; 
    } 
} 

Table t1(3); 
t1(4); 

Répondre

7

La réponse est une fonctionnalité de langage merveilleux appelé affectation. En résumé, vous pouvez modifier la valeur d'une variable – même une variable d'un type que vous avez vous-même défini – en utilisant le symbole =.

En fait votre code est en utilisant déjà l'affectation, à savoir dans le constructeur.Dans l'exemple ci-dessous, j'ai remplacé l'affectation de ce code original par un initialiseur, car les initialiseurs sont généralement préférables (choisissez-les lorsqu'il n'y a pas de bonnes raisons d'utiliser l'affectation pour l'initialisation des membres).

L'affectation qui met à jour la valeur de t1, efficace "réutilisation" t1, peut se présenter comme suit:

class Table 
{ 
private: 
    int feet; 
public: 
    Table(int x): feet(x) {} 
}; 

Table t1(3); 
t1 = Table(4); 

Note 1: il est possible de définir un type de telle sorte que la cession est interdite.

Note 2: puisque vous avez défini un constructeur de conversion , qui accepte un seul argument, et puisque ce constructeur n'est pas explicit, l'affectation peut être exprimé plus simplement ci-dessus (mais peut-être moins clairement) que & hellip ;

t1 = 4; 

& hellip; ce qui entraîne exactement la même chose.

Note 3: votre code tel que présenté ne l'aurait pas compilé, c'était juste "comme" C++, ce n'était pas C++. J'ai corrigé les erreurs (je pense, mais je n'ai pas pris la peine de passer par un compilateur). Mais en général, il n'est pas toujours possible de savoir ou même de deviner si des erreurs dans le code présenté ont quelque chose à voir avec la question, alors s'il vous plaît copiez et collez du code réel.

Vive & HTH.,

+0

J'aime cette réponse. :) +1 de moi. –

+1

Wow.Ça a vraiment marché. Merci! – Kaimde

+1

Je vais sortir d'un membre et deviner que le code réel est beaucoup plus compliqué que l'extrait montré, auquel cas l'opérateur d'assignation fourni par le compilateur peut ne pas être adéquat, et un opérateur d'assignation défini par l'utilisateur peut finir dupliquer une grande partie du code du destructeur de tables et du constructeur. C'est là que le swap serait utile, pour éliminer cette duplication de code, et fournir une sécurité d'exception. –

1

Je suggère d'utiliser à la place the swap idiom, mais si vous voulez vraiment recréer un nouvel objet dans la même variable , utilisez le placement nouveau:

Table t1(3); 
t1.~Table(); 
new (&t1) Table(4); 

Le placement nouveau construit simplement un objet dans la mémoire que vous fournissez, sans faire aucune allocation.

Si vous décidez d'aller avec swap, vous devrez écrire la fonction d'échange, puis de faire le reinstantiation:

Table t1(3); 
Table(4).swap(t1); 
+6

Ceci est une technique extrêmement dangereuse. Ce n'est pas quelque chose à suggérer à un débutant. –

+0

@Alf: C'est pourquoi ma réponse commence par suggérer une manière plus simple. –

+0

@Alf: Pourriez-vous expliquer ce qui est dangereux à ce sujet? – Kaimde

0

Pourquoi voulez-vous reinstanciate? Ce n'est pas RAII.

L'instanciation consiste à obtenir de l'espace pour l'objet, puis à appeler le constructeur. Si vous voulez simplement changer les valeurs des membres, ou appeler une méthode, créez une méthode init et appelez-la à partir du constructeur et quand vous voulez réinitialiser l'objet. Cela fonctionne dans des cas simples car le bus n'est pas exactement comme un constructeur. Certaines choses (comme l'initialisation des membres de référence) peuvent être effectuées uniquement dans la liste d'initialisation qui n'existe que dans le constructeur.

Et évidemment vous devriez faire attention, car les destructeurs doivent être appelés pour les variables membres avant de les réattribuer.

Le placement de nouveau fonctionnerait également, mais il semble que vous soyez surchargé, vous n'en obtiendrez pas plus qu'avec l'appel d'une méthode simple pour réinitialiser l'objet. Et c'est dangereux car cela peut conduire à des bugs très délicats.

SWAP Idiom comme suggéré par Ben Voight est probablement le meilleur choix que vous avez si vous allez sur la surcharge de la piste de l'opérateur d'affectation.

Mon conseil sur la réinstanciation est ne pas.

Quel est le problème avec l'utilisation d'une nouvelle instance et en laissant l'ancienne seule? Réutiliser les mêmes variables pour différentes tâches était déjà une mauvaise idée avec C car cela rend l'optimisation du compilateur plus difficile. C'est toujours avec C++, et c'est aussi dangereux car vous pouvez facilement oublier d'appeler destructeur du premier objet et aller dans les ennuis.

Il y a des cas où vous auriez besoin de faire cela, comme si vous preniez l'adresse de l'objet, et que vous vouliez changer ses membres. Mais dans de tels cas, il est probablement préférable de changer votre code pour éviter de le faire de toute façon. Je ne vois pas de cas réel où cela serait nécessaire. S'il y a, je suis curieux de savoir.

+1

Toutes les classes C++ ne sont pas RAII, car toutes les classes C++ ne gèrent pas les ressources. –

+0

En outre, la * ctor-initializer-list * ne fonctionne que dans le constructeur, pas une méthode d'initialisation à laquelle elle délègue. –

+0

Oui, vous ne pouvez pas simuler la liste d'initialisation de ctor, et si vous utilisez des membres de référence, ce que je propose ne sera pas suffisant. Je vais éditer ma réponse. – kriss

0

La réponse ne preferred résout pas le problème assez bien. L'affectation ne réinstalle pas réellement l'objet, elle effectue simplement une affectation. Dans l'exemple, si feet devait être const, la solution ne compilera pas.

Une solution plus délicate serait l'utilisation "Placement new"/"Placement syntax" comme:

Table t1(3); 
t1.~Table(); 
new (&t1) Table(4);