Je crée une classe de type chaînage, comme le petit exemple ci-dessous. Il semble que lors du chaînage des fonctions membres, le constructeur de copie soit invoqué. Existe-t-il un moyen de se débarrasser de l'appel du constructeur de copie? Dans mon exemple de jouet ci-dessous, il est évident que je ne traite que des temporaires et donc il "devrait" (peut-être pas selon les normes, mais logiquement) être une élision. Le deuxième meilleur choix, pour copier l'élision, serait d'appeler le constructeur de déplacement, mais ce n'est pas le cas.
class test_class {
private:
int i = 5;
public:
test_class(int i) : i(i) {}
test_class(const test_class& t) {
i = t.i;
std::cout << "Copy constructor"<< std::endl;
}
test_class(test_class&& t) {
i = t.i;
std::cout << "Move constructor"<< std::endl;
}
auto& increment(){
i++;
return *this;
}
};
int main()
{
//test_class a{7};
//does not call copy constructor
auto b = test_class{7};
//calls copy constructor
auto b2 = test_class{7}.increment();
return 0;
}
Edit: Quelques clarifications. 1. Cela ne dépend pas du niveau d'optimisation. 2. Dans mon vrai code, j'ai des objets plus complexes (par exemple alloués par tas) que des entiers
auto b = test_class{7};
n'appelle pas le constructeur de copie car il est vraiment équivalent àtest_class b{7};
et les compilateurs sont assez intelligents pour reconnaître ce cas et peuvent donc facilement éluder toute copie. On ne peut pas faire la même choseb2
.std::cout
) dans votre ctor de copie? Sans cela, la copie devrait être optimisée.Réponses:
Réponse partielle (elle ne se construit pas
b2
sur place, mais transforme la construction de copie en construction de déplacement): vous pouvez surcharger laincrement
fonction membre sur la catégorie de valeur de l'instance associée:Ce qui provoque
déplacer-construire
b2
cartest_class{7}
est temporaire et la&&
surcharge detest_class::increment
est appelée.Pour une véritable construction sur place (c'est-à-dire même pas une construction de déplacement), vous pouvez transformer toutes les fonctions membres spéciales et non spéciales en
constexpr
versions. Ensuite, vous pouvez faireet vous n'avez ni un déménagement ni une copie à payer. C'est évidemment possible pour le simple
test_class
, mais pas pour un scénario plus général qui ne permet pas lesconstexpr
fonctions membres.la source
b2
non modifiable.constinit
serait la façon d'y aller.this
est identique aux fonctionsconst
membresFondamentalement, l'attribution d'une référence à une valeur nécessite l'invocation d'un constructeur, c'est-à-dire une copie ou un déplacement . Ceci est différent de la copie-élision où il est connu des deux côtés de la fonction d'être le même objet distinct. Une référence peut également faire référence à un objet partagé un peu comme un pointeur.
Le moyen le plus simple est probablement de rendre le constructeur de copie entièrement optimisé. Le paramètre de valeur est déjà optimisé par le compilateur, c'est juste celui
std::cout
qui ne peut pas être optimisé.(ou supprimez simplement le constructeur de copie et de déplacement)
exemple en direct
Étant donné que votre problème concerne essentiellement la référence, une solution ne renvoie probablement pas de référence à l'objet si vous souhaitez arrêter la copie de cette manière.
Une troisième méthode repose simplement sur la suppression de la copie en premier lieu - cependant cela nécessite une réécriture ou une encapsulation de l'opération dans une fonction et évitant ainsi complètement le problème (je sais que ce n'est peut-être pas ce que vous voulez, mais pourrait être un solution aux autres utilisateurs):
Une quatrième méthode utilise un mouvement à la place, soit explicitement invoqué
ou comme on le voit dans cette réponse .
la source