par , 22/06/2017 à 14h03 (1243 Affichages)
Récemment je me suis demandé comment initialiser proprement une classe avec les différents constructeurs et opérateurs de copie/affection proprement, sans dupliquer le code, étant donné que la classe ne compte aucun pointeur nu. Je me suis donc orienté sur le forum de developpez. La réponse citée vient du topic que j'ai crée à ce sujet.
Et je dois dire que j'ai appris pas mal de choses durant cette discussion, dont notamment :
- l'utilisation de std::move (header <utility>) pour gérer proprement le transfert
- le 4e constructeur (dont j'ignorais complètement l'existence)
Bref, cela a été pour moi une excellente occasion de renforcer mes connaissances et mes bonnes pratiques.
Page de la discussion originale
Envoyé par
tails
Bonjour à tous
J'ai besoin de créer un constructeur par copie dans une classe personnelle, et deux opérateurs d'affectations (un avec une R-Value), mais j'ai dû dupliquer le code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
Operation::Operation(const Operation &valueToCopy){
this->_operator = valueToCopy._operator;
this->_tile_1 = valueToCopy._tile_1;
this->_tile_2 = valueToCopy._tile_2;
}
Operation& Operation::operator=(Operation&& valueToCopy){
this->_operator = valueToCopy._operator;
this->_tile_1 = valueToCopy._tile_1;
this->_tile_2 = valueToCopy._tile_2;
return *this;
}
Operation& Operation::operator=(const Operation& valueToCopy){
this->_operator = valueToCopy._operator;
this->_tile_1 = valueToCopy._tile_1;
this->_tile_2 = valueToCopy._tile_2;
return *this;
} |
(Si vous vous demandez pourquoi les 3, c'est simplement pour mieux utiliser la STL, elles paraissent indispensables pour utiliser les méthodes de certaines collections).
Comment faire plus simple, factoriser tout cela en réutilisant l'une des 3 méthodes dans les deux autres ? J'avais vu dans un cours, mais j'ai carrément oublié.
Autre question liée : vu que je n'utilise pas de pointeur nu dans ma classe, je n'ai pas besoin de surcharger le destructeur : n'est-ce pas ?
Envoyé par
dalfab
Je ne vois pas du tout l’intérêt de ces fonctions qui ne font que ce que font les fonctions par défaut. Mais en nettement moins optimal!
Voilà le code qui est utilisé si ces fonctions ne sont jamais déclarés ou si elles sont définies en "= default" :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Operation::Operation( const Operation &valueToCopy )
: _operator(valueToCopy._operator),
_tile_1(valueToCopy._tile_1) , _tile_2(valueToCopy._tile_2) {
// crée les 3 membres et les initialise en même temps
}
Operation& Operation::operator=( Operation&& valueToCopy ) {
this->_operator = std::move(valueToCopy._operator);
this->_tile_1 = std::move(valueToCopy._tile_1);
this->_tile_2 = std::move(valueToCopy._tile_2);
// fait un transfert des éléments au lieu d'une simple copie
return *this;
}
Operation& Operation::operator=( const Operation &valueToCopy ) {
// peut utiliser un swap par exemple ou
if ( &valueToCopy != this ) {
this->_operator = valueToCopy._operator;
this->_tile_1 = valueToCopy._tile_1;
this->_tile_2 = valueToCopy._tile_2;
}
return *this;
}
// et il manque une quatrième, le constructeur par transfert
Operation::Operation( Operation&& valueToMove )
: _operator(std::move(valueToMove._operator)),
_tile_1(std::move(valueToMove._tile_1)) , _tile_2(std::move(valueToMove._tile_2) {
} |