Construire un objet avec l'opérateur d'assignation
Bonjour,
Jusqu'à maintenant voilà comment je procédais pour instancié mes objets :
Code:
1 2 3 4 5 6 7 8
|
// sur la pile, statique
MyObject instanceA;
MyObject instanceB(42, "cpp_qt_lover");
// sur le tas, dynamique
MyObject* instanceA = new MyObject();
MyObject* instanceB = new MyObject(42, "cpp_qt_lover"); |
Voilà, comme j'étais un peu fatigué et que je voulais ne plus utilisé d'allocation dynamique, j'ai transformé le code suivant :
Code:
1 2 3
|
MyObject* instanceA = new MyObject();// original
MyObject instanceA = MyObject();// retiré le new et l'opérateur* |
Et surprise, là ou je m'attendais à une erreur du compilateur, et bien tout fonctionnait... Je voulais savoir si c'était une autre façon de faire ou si sa signifiait autre chose... Merci d'avance pour vos réponses.
C'est dans l'accessibilité privée que l'on déclare le constructeur par copie et l'opérateur d'affectation...
Citation:
Envoyé par
Goten
En fait ce genre de code :
T t = T();
n'appelle pas l'op= mais le constructeur par recopie. ;).
Et encore... si (N)RVO ( (Named) Return Value Optimisation) ne passe pas par là :aie:
Avec le phénomène (N)RVO qui est quand même implémenté par pas mal de compilateur, il se peut que le seul constructeur par défaut soit appelé:D
@Abdelite>> Ce qu'il faut comprendre, c'est que, tant que tu ne lui donne pas de raison d'agir autrement, le compilateur va systématiquement implémenter la forme canonique de Coplien pour toutes les classes / structures qu'il rencontre.
C'est à dire qu'il implémentera de manière implicite (sans que tu ne fasse quoi que ce soit) quatre fonctions particulières:
- le constructeur par défaut (ne prenant pas d'argument)
- le constructeur par copie
- le destructeur
- l'opérateur d'affectation
Il n'y a donc, a priori, aucune raison pour qu'il rechigne à copier ou à affecter une instance d'une classe à une variable dont le type est compatible :D
Pour que le compilateur renonce à fournir l'implémentation d'une de ces fonctions, il "suffit" de la déclarer, ou, pour le constructeur par défaut, de déclarer n'importe quel constructeur qui ne soit pas constructeur par copie.
Le compilateur fournira alors le code binaire de la fonction en question sur base... de l'implémentation que tu en auras (éventuellement) donnée.
C'est la raison pour laquelle, lorsque l'on crée une classe non copiable et / ou non assignable, on se contente de déclarer le constructeur par copie et / ou l'opérateur d'affectation dans l'accessibilité privée sans les implémenter.
Dans la majorité des cas (comprend: tant que l'on est dans une situation dans laquelle on n'a pas accès à la partie private de la classe) cette simple manoeuvre permet d'obtenir une erreur proche de "le constructeur par copie (ou l'opérateur d'affectation) est private dans ce contexte"
Une minorité de cas peut cependant avoir accès à cette déclaration private du constructeur par copie / de l'opérateur d'affectation: Lorsque l'on se trouve dans une fonction membre de la classe ou dans une fonction pour laquelle l'amitié avec la classe s'applique.
L'erreur sera alors reportée à l'étape d'édition de liens, l'éditeur de liens se plaignant d'un "symbole indéfini", car le symbole du constructeur par copie / de l'opérateur d'affectation existant, mais l'éditeur de liens ne trouve aucun code binaire correspondant.
La nouvelle norme ajoute la possibilité de dire de manière explicite que l'une de ces fonctions n'existe pas (NB: une classe que l'on ne pourrait pas construire ou que l'on ne pourrait pas détruire n'a strictement aucun intérêt, hein :question: cette possibilité n'a donc d'intérêt que pour le constructeur par copie ou l'opérateur d'affectation :D) en ajoutant = delete après la déclaration:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class NonCopiable
{
public:
NonCopiable(); // constructeur par défaut
NonCopiable(NonCopiable const &) = delete; // uniquement en C++1x
NonCopiable & operator = (NonCopiable const &) = delete; //uniquement en C++1x
/* si on ne déclare pas le destructeur, le compilateur l'ajoute
* automatiquement et le rend public et non virtuel
*/
private:
/* rendent la classe non copiable / non affectable
* !!! pour que ce soit effectivement le cas, on ne fournit pas
* d'implémentation pour ce qui suit :D
*/
NonCopiable(NonCopiable const &); /* valide depuis toujours */
NonCopiable & operator= (NonCopiable const &); /* idem */
}; |