6
votes

Passer par valeur ou référence à un constructeur C ++ qui doit stocker une copie?

Si un constructeur de valeur C ++ (implicite ou explicite) accepte son (s) paramètre (s) par valeur ou référence-to-const, lorsqu'il doit stocker une copie de l'argument (s) de l'article (s) de l'autre?

Voici l'exemple le plus court que je peux penser: P>

foo f = function_that_creates_and_returns_a_bar_object_using_rvo();


0 commentaires

8 Réponses :


-1
votes

Tenez un Shared_pointer à la barre de votre classe et transmettez-la comme telle. De cette façon, vous n'appelez jamais le constructeur de copie :).


1 commentaires

Ce qui est très léger ... inquiétant de cela serait un cas d'optimisation prématurée si jamais j'en ai entendu parler d'un. J'essayais juste de fournir une approche différente :)



4
votes

Regarde ce Question .

Utiliser const t & arg Si Tailleof (t)> Tailleof (Void *) et utilisez T arg si Sizeof ( T) <= tailleOf (vide *) . Tous les types fondamentaux devraient être l'exception à cette règle


4 commentaires

Bien que je pense que c'est une bonne règle, il semble qu'il semble entrer en conflit avec la ligne directrice présentée par l'article référencé (au moins parfois parfois) ... et dans mon étui d'utilisation spécifique, FOO est un modèle de classe avec une barre comme paramètre de modèle, Je ne connais donc pas la taille de (bar) (peut-être que j'aurais dû inclure cela dans mon exemple :().


Utilisez des traits de type pour choisir la référence ou la valeur en fonction de la taille de (bar)


@Alexey: À l'exception des foncteurs et des itérateurs (selon Meyers) qui devrait toujours être adopté par la valeur et nous espérons alors que le compilateur fait la bonne chose. Je ne sais pas ce que Meyers a fumé pour arriver à cette conclusion, cependant.


@Alexey: Bon point sur les traits de type. Je peux voir où les traits de type pourraient fournir quelque chose comme valeur_or_connst_ref :: Type, qui pourrait générer une barre si la barre est un type intégré ou si la taille de la taille (bar) <= tailleof (vide *), ou peut-être si Tailleof ( bar) <= la taille de l'un des types intégrés et entraîner une barre constante et. (Et cela invalide mon point précédent que je ne peux pas supposer, je connais la taille de (bar).)



1
votes

Je suppose que bar a un constructeur de copie normal du formulaire bar (const Bar & B)

Prenez une référence de const ici. La barre S prendra ensuite cette référence et effectuera la copie. Total des copies: 1.

Si vous avez quitté la référence, le compilateur effectuerait une copie de B, transmettre la copie sur le constructeur de code FOO , qui le transmettrait ensuite à bar et Copiez cela.


0 commentaires

5
votes

Toutes choses étant égales, je passe par Const & pour des classes suffisamment complexes, et de la valeur pour les objets et objets simples.

Position des avantages / inconvénients à réussir par une référence de const au lieu d'une carte traditionnelle par valeur

positifs:

  • évite une copie (gros plus pour les objets avec une copie coûteuse)
  • Accès en lecture seule

    négatifs:

    • quelqu'un peut const jeter le const hors de la référence si ils voulaient vraiment

      Plus important encore avec les positifs est votre commande lorsque la copie se produit (dans votre cas lors du passage d'initialisation _B dans votre liste d'initialisateur). Penser aux négatifs ... Je suis d'accord c'est un risque. Je pense que presque tous les bons programmeurs se sentiront sales à l'élimination du const_cast. De plus, vous pouvez rechercher consciencieusement Const_cast et lancer des tomates à la personne qui coule le const hors de l'argument. Mais bon, vous ne savez jamais et qui a le temps de regarder le code comme un faucon :)?

      Mon opinion subjective est que dans des classes et dans des environnements suffisamment complexes, où la performance compte l'avantage d'éviter le constructeur de copie l'emporte sur le risque. Cependant, pour des classes vraiment stupides et de Pod, j'ai tendance à faire des copies des données et à réussir par la valeur.


0 commentaires

0
votes

Honnêtement, dans ce cas, la meilleure option consiste à rendre votre constructeur inline , fourni le constructeur de bar ne jette pas. Puis passer juste à titre de référence.

Aussi, comme vous le soupçonnez, votre article ne s'applique pas ici.


0 commentaires

2
votes

Stylistiquement, je dirais que le passage par référence est la meilleure façon.

Si la performance importe vraiment, alors ne devinez pas. Mesurez-le.


1 commentaires

+1 pour recommander des performances de mesure au lieu de deviner.



2
votes

Je n'ai pas vérifié ce que la norme dit, mais en essayant ceci empiriquement, je peux vous dire que GCC n'oblise pas la copie à l'écart, que le constructeur accepte l'argument par valeur ou par Constons référence.

Si Cependant, le constructeur prend une référence const, il parvient à éviter une copie inutile lorsque vous créez foo à partir d'un objet bar existant.

résumer : xxx

pas que je suis un expert en compilateur, mais je suppose qu'il est logique qu'il ne puisse généralement pas rvo une valeur de retour dans un lieu arbitraire (tel que le champ membre de l'objet foo ). Au lieu de cela, il faut que la cible soit sur le dessus de la pile.


0 commentaires

2
votes

in c ++ 98 et C ++ 03, vous devez passer const & bar code>, puis copier. En C ++ 0x, vous devez passer bar code> puis faire un déplacement (à fournir bar code> a un constructeur de déplacement).

#include <utility>

struct foo
{
    bar _b;

    foo(bar b) : _b(std::move(b)) {}
};


1 commentaires

J'envisage cela la réponse parce que c'est la plus éprouvante, et cela montre comment il s'agit d'une déficience en C ++ 98/03 qui sera résolue par C ++ 0x. Cependant, voir la réponse d'Alexey Malistov (et des commentaires suivants) pour des cas où vous voudrez peut-être passer de valeur pour C ++ 98/03.