Parfois plus optimal, mais d'autres fois moins.
Je viens de tester ce code sur le site
Coliru :
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| #include <iostream>
#include <string>
struct ObjetSimple
{
std::string m_data;
ObjetSimple(const std::string& data) : m_data(data)
{
std::cout << "ObjetSimple : constructeur\n";
}
ObjetSimple(const ObjetSimple& other) : m_data(other.m_data)
{
std::cout << "ObjetSimple : constructeur de recopie\n";
}
ObjetSimple(ObjetSimple&& other) : m_data(std::move(other.m_data))
{
std::cout << "ObjetSimple : constructeur de mouvement\n";
}
ObjetSimple& operator=(const ObjetSimple& other)
{
m_data = other.m_data;
std::cout << "ObjetSimple : affectation de recopie\n";
return *this;
}
ObjetSimple& operator=(ObjetSimple&& other)
{
m_data = std::move(other.m_data);
std::cout << "ObjetSimple : affectation de mouvement\n";
return *this;
}
~ObjetSimple()
{
std::cout << "ObjetSimple : destructeur\n";
}
};
struct ParReference
{
ObjetSimple m_objet;
ParReference(const ObjetSimple& objet) : m_objet(objet) // PAR REFERENCE CONSTANTE
{
std::cout << "ParReference : constructeur\n";
}
ParReference(const ParReference& other) : m_objet(other.m_objet)
{
std::cout << "ParReference : constructeur de recopie\n";
}
ParReference(ParReference&& other) : m_objet(std::move(other.m_objet))
{
std::cout << "ParReference : constructeur de mouvement\n";
}
ParReference& operator=(const ParReference& other)
{
m_objet = other.m_objet;
std::cout << "ParReference : affectation de recopie\n";
return *this;
}
ParReference& operator=(ParReference&& other)
{
m_objet = std::move(other.m_objet);
std::cout << "ParReference : affectation de mouvement\n";
return *this;
}
~ParReference()
{
std::cout << "ParReference : destructeur\n";
}
};
struct ParValeur
{
ObjetSimple m_objet;
ParValeur(ObjetSimple objet) : m_objet(std::move(objet)) // PAR VALEUR
{
std::cout << "ParValeur : constructeur\n";
}
ParValeur(const ParValeur& other) : m_objet(other.m_objet)
{
std::cout << "ParValeur : constructeur de recopie\n";
}
ParValeur(ParValeur&& other) : m_objet(std::move(other.m_objet))
{
std::cout << "ParValeur : constructeur de mouvement\n";
}
ParValeur& operator=(const ParValeur& other)
{
m_objet = other.m_objet;
std::cout << "ParValeur : affectation de recopie\n";
return *this;
}
ParValeur& operator=(ParValeur&& other)
{
m_objet = std::move(other.m_objet);
std::cout << "ParValeur : affectation de mouvement\n";
return *this;
}
~ParValeur()
{
std::cout << "ParValeur : destructeur\n";
}
};
static ParReference fooParReference() {ObjetSimple obj("toto"); return ParReference(obj);}
static ParValeur fooParValeur() {ObjetSimple obj("toto"); return ParValeur (obj);}
static ParReference barParReference() {return ParReference(ObjetSimple("toto"));}
static ParValeur barParValeur() {return ParValeur (ObjetSimple("toto"));}
int main()
{
std::cout << "Version de g++ : " __VERSION__ << "\n\n";
std::cout << "Avec les fonctions foo, c'est mieux par référence :\n\n";
fooParReference();
std::cout << "\n";
fooParValeur();
std::cout << "\n";
std::cout << "Avec les fonctions bar, c'est mieux par valeur :\n\n";
barParReference();
std::cout << "\n";
barParValeur();
return 0;
} |
Options de compilation :
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Sortie :
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 30 31 32 33 34 35
| Version de g++ : 6.1.0
Avec les fonctions foo, c'est mieux par référence :
ObjetSimple : constructeur
ObjetSimple : constructeur de recopie
ParReference : constructeur
ObjetSimple : destructeur
ParReference : destructeur
ObjetSimple : destructeur
ObjetSimple : constructeur
ObjetSimple : constructeur de recopie
ObjetSimple : constructeur de mouvement
ParValeur : constructeur
ObjetSimple : destructeur
ObjetSimple : destructeur
ParValeur : destructeur
ObjetSimple : destructeur
Avec les fonctions bar, c'est mieux par valeur :
ObjetSimple : constructeur
ObjetSimple : constructeur de recopie
ParReference : constructeur
ObjetSimple : destructeur
ParReference : destructeur
ObjetSimple : destructeur
ObjetSimple : constructeur
ObjetSimple : constructeur de mouvement
ParValeur : constructeur
ObjetSimple : destructeur
ParValeur : destructeur
ObjetSimple : destructeur |
Pour éviter une copie, il y a deux solutions simples :
1) La classe
Spell contient des pointeurs ou des références vers des
std::vector<DmgRoll> au lieu de contenir directement les
std::vector<DmgRoll>. Cela permet d'éviter de copier les objets
std::vector<DmgRoll>. Il faudra cependant faire attention à ce que l'objet
Spell soit détruit avant les objets
std::vector<DmgRoll>. Sinon, l'objet
Spell aura des pointeurs ou des références vers des
std::vector<DmgRoll> qui n'existent plus.
2) La classe
Spell contient des
std::vector<DmgRoll> initialement vides. Tu les remplis ensuite progressivement via des fonctions de
Spell qui appellent
std::vector<DmgRoll>::push_back(). Cette solution a un sens si les éléments ajoutés au fur et à mesure ne sont pas déjà tous dans un
std::vector<DmgRoll> avant la création de l'objet
Spell.
Partager