Is het in C++ nog steeds een slechte gewoonte om een ​​vector van een functie te retourneren?

Korte versie:het is gebruikelijk om in veel programmeertalen grote objecten, zoals vectoren/arrays, te retourneren. Is deze stijl nu acceptabel in C++0x als de klasse een move-constructor heeft, of vinden C++-programmeurs het raar/lelijk/gruwel?

Lange versie:Wordt dit in C++0x nog steeds als een slechte vorm beschouwd?

std::vector<std::string> BuildLargeVector();
...
std::vector<std::string> v = BuildLargeVector();

De traditionele versie ziet er als volgt uit:

void BuildLargeVector(std::vector<std::string>& result);
...
std::vector<std::string> v;
BuildLargeVector(v);

In de nieuwere versie is de waarde die wordt geretourneerd door BuildLargeVectoreen rvalue, dus v zou worden geconstrueerd met behulp van de move-constructor van std::vector, ervan uitgaande dat (N) RVO vindt niet plaats.

Zelfs vóór C++0x was de eerste vorm vaak “efficiënt” vanwege (N)RVO. (N)RVO is echter ter beoordeling van de samensteller. Nu we rvalue-referenties hebben, is het gegarandeerddat er geen diepe kopie zal plaatsvinden.

Bewerken: de vraag gaat niet echt over optimalisatie. Beide getoonde vormen hebben bijna identieke prestaties in real-world programma’s. Terwijl in het verleden de eerste vorm in orde van grootte slechtere prestaties had kunnen hebben. Als gevolg hiervan was de eerste vorm lange tijd een grote codegeur in C++-programmering. Niet meer, hoop ik?


Antwoord 1, autoriteit 100%

Dave Abrahams heeft een behoorlijk uitgebreide analyse van de snelheid van het doorgeven/teruggeven van waarden.

Kort antwoord, als u een waarde moet retourneren, retourneer dan een waarde. Gebruik geen uitvoerreferenties omdat de compiler het toch doet. Natuurlijk zijn er kanttekeningen, dus je moet dat artikel lezen.


Antwoord 2, autoriteit 50%

Tenminste IMO, het is meestal een slecht idee, maar nietom efficiëntieredenen. Het is een slecht idee omdat de functie in kwestie meestal moet worden geschreven als een generiek algoritme dat de uitvoer via een iterator produceert. Bijna elke code die een container accepteert of retourneert in plaats van op iterators te werken, moet als verdacht worden beschouwd.

Begrijp me niet verkeerd: soms is het logisch om collectie-achtige objecten (bijv. strings) door te geven, maar voor het genoemde voorbeeld zou ik het doorgeven of retourneren van de vector een slecht idee vinden.

>


Antwoord 3, autoriteit 24%

De kern is:

Copy Elision en RVO kunnende “enge kopieën” vermijden (de compiler hoeft deze optimalisaties niet te implementeren en kan in sommige situaties niet worden toegepast)

C++ 0x RValue-referenties sta toeeen string/vector-implementatie die garandeertdat.

Als je oudere compilers / STL-implementaties kunt verlaten, retourneer dan vrij vectoren (en zorg ervoor dat je eigen objecten dit ook ondersteunen). Als je codebasis “mindere” compilers moet ondersteunen, blijf dan bij de oude stijl.

Helaas heeft dat grote invloed op uw interfaces. Als C++ 0x geen optie is en u garanties nodig hebt, kunt u in sommige scenario’s in plaats daarvan referentie-getelde of copy-on-write-objecten gebruiken. Ze hebben echter nadelen aan multithreading.

(Ik wou dat slechts één antwoord in C++ eenvoudig en duidelijk en zonder voorwaarden zou zijn).


Antwoord 4, autoriteit 4%

Om een ​​beetje te muggenziften: het is in veel programmeertalen niet gebruikelijk om arrays van functies te retourneren. In de meeste van hen wordt een verwijzing naar array geretourneerd. In C++ zou de dichtstbijzijnde analogie zijn: boost::shared_array


Antwoord 5, autoriteit 3%

Als prestaties een echt probleem zijn, moet u zich realiseren dat de verplaatsingssemantiek niet altijdsneller is dan kopiëren. Als u bijvoorbeeld een tekenreeks heeft die gebruikmaakt van de kleine tekenreeksoptimalisatie, dan moet een verplaatsingsconstructor voor kleine tekenreeksen exact dezelfde hoeveelheid werk doen als een gewone kopieerconstructor.

Other episodes