2013-03-28 4 views
3

Prenez la fonction suivante comme exemplemeilleur moyen de passer des objets volumineux

string print() 
{ 
    return (some string that has been formed); 
}; 

et permet maintenant de dire que cette fonction d'impression formera une chaîne ridiculement grande, qui doit revenir à la fonction qui l'a appelé à partir une autre classe.

Maintenant, dites que cette fonction d'impression peut être appelée des milliers de fois. Y a-t-il un moyen correct et rapide de le faire?

Dans Visual Studio, vous pouvez le faire

void print(string& lines) 
{ 
    lines = (some string that has been formed); 
}; 

cependant g ++ ne compilera pas cela, il ne devrait pas être fait de cette façon que cela pourrait être un objet temporaire qui pourrait disparaître à tout instant. D'après ce que je comprends est que je pouvais faire ce

void print(const string& lines) 
{ 
}; 

si tout ce que je voulais était de récupérer quelque chose dans cette chaîne w/o modifier et de le faire très rapidement. Mais je veux le modifier. Donc, je ne peux pas faire ça.

Ce qui m'amène à la question est de déclarer un nouveau pointeur sur un objet qui sera le moyen le plus rapide de le faire? ou est-ce plus lent? ou est-ce que ça ne vaut pas le coup. à-dire (pas sûr si cela même travail?)

void print(string* lines) 
{ 
    string formedString; // the string that has been formed 
    lines = formedString&; 
}; 

Et enfin, si je suis le chargement objet vers le haut lors de l'exécution, et en les ajoutant à un arbre via:

void add(const ItemType& item) 
{ 
    someNode->item = item; 
}; 

Le item était à l'origine une objet temporairement stocké dans la portée de la fonction appelant ce add(), donc l'affecterait au nœud provoquer la pile de la fonction d'appel à rester plus longtemps alors voulu? Ou serait-ce OK? Aussi serais-je plus tard en mesure d'éditer item, ou est-il maintenant coincé comme const?

seulement des questions d'un esprit d'apprentissage :)

+1

Retournez la grande chaîne que vous formez en valeur. – chris

+3

Vous pouvez allouer la chaîne sur heap et renvoyer le pointeur sur la chaîne. OU l'appelant à la méthode pourrait être responsable de passer la méthode un point à l'endroit où la chaîne peut être stockée. L'un ou l'autre est assez rapide. Au fait, ne vous inquiétez pas des performances si votre code n'est pas lent. – Patashu

+1

** La pré-optimisation est la racine de tout mal ** est quelque chose qu'un esprit d'apprentissage devrait tenir compte. – Aesthete

Répondre

8

juste retour la chaîne et faire avec elle.

Le compilateur utilisera l'optimisation de la valeur de retour (ou l'optimisation de la valeur de retour nommée) pour éliminer les copies supplémentaires de la chaîne lorsque vous la renvoyez. Un compilateur vraiment nouveau aura aussi un constructeur de mouvement et un opérateur d'assignation de mouvement pour std::string, ce qui donnera une plus grande assurance d'accomplir la même chose. Éditer (désolé, j'ai d'abord manqué la dernière question): assigner une valeur pas préserver quelque chose de local à une fonction après le retour de cette fonction. Lorsqu'une fonction retourne, toutes ses variables locales seront détruites. Si vous affectez une valeur de cette fonction à quelque chose qui dure après son retour, ce n'est pas un problème - il sera copié (ou peut-être déplacé) vers la destination. Si vous conservez un pointeur ou une référence à ce local, il sera suspendu après le retour de la fonction, donc essayer d'utiliser la référence ou déréférencer le pointeur conduira à UB.

En fonction de la situation, ce dernier peut être un cas où vous souhaitez utiliser un shared_ptr, donc à la fois la fonction et le code extérieur partagera l'accès aux données, et les données seront détruites que lorsque à la fois les références à celui-ci sont détruites.

+0

qu'en est-il de ma dernière question où vous avez un type générique, et qui le stockera plus tard alors la portée de la fonction qui a déclaré qu'il peut durer? passer cela par valeur ou par référence const? (Je sais que la référence est la valeur de l'adresse) – WIllJBD

2

En C++ 11, ou un compilateur de base avec 11 fonctionnalités C++, la réponse est:

Vous voulez la vitesse? Passer en valeur, avec des objets qui supportent la sémantique de déplacement.

Et votre type string (que ce soit un std::string ou autre) devrait prendre en charge la sémantique de déplacement rapide.

Si vous renvoyez une variable locale d'une fonction, sous C++ 11, elle sera implicitement déplacée dans la valeur de retour. Si le corps de votre fonction est visible depuis le site des appelants, et que vous avez une variable qui est une valeur de retour de votre fonction, alors NRVO peut se produire sans qu'aucune copie ou déplacement ne se produise (mais plutôt l'objet est construit là où il finit dans le site appelant).

Chaque fois que vous voulez éventuellement faire une copie de l'argument passé, utilisez de la même façon une valeur de transfert dans le paramètre. Cela peut permettre à l'appelant de faire un pas-à-pas dans quelques contextes, et l'appelant peut explicitement std::move dans les contextes non automatiques, pour donner de bonnes performances.

Si vous ne faites pas de copie, passez par const string&, qui peut être liée à un fichier temporaire.

Si vous modifiez des données, que ce soit par passe string&ou passe par string, puis retournez la nouvelle chaîne dans le cadre de la valeur de retour. Avec la construction de mouvement rapide, la seconde est presque aussi rapide que la première dans le pire des cas, et dans certains cas peut être plus rapide (plusieurs chaînes de NRVO sont théoriquement possibles avec ce second cas!)

+0

donc avec mon 'item', vous dites que je devrais le passer en valeur plutôt qu'une référence' const Item Item ', pour la raison que je veux stocker/copier/modifier plus tard? Donc, si j'ai passé 'item' par référence const, cela serait-il mauvais dans le cas où je le stockerais plus tard, alors la portée de la fonction qui a déclaré qu'il pourrait durer? – WIllJBD

+1

Si vous allez stocker quelque chose, et qu'il a un constructeur 'move' rapide, votre fonction devrait le prendre en valeur - avoir des roches rapides. Et oui, garder des références non traquées sur les choses est dangereux et une céphalée de maintenance: dans certaines situations, c'est encore fait, mais cela demande de l'attention. – Yakk

Questions connexes