2017-01-18 7 views
6

Ich lese auf Kopie Elision (und wie es in C++ 17 garantiert werden soll) und dies hat mich ein wenig verwirrt (ich bin mir nicht sicher, ich weiß Dinge, die ich dachte, ich wusste vorher). So ist hier ein minimaler Testfall:Was passiert in dieser Rückmeldung?

std::string nameof(int param) 
{ 
    switch (param) 
    { 
    case 1: 
     return "1"; // A 
    case 2: 
     return "2" // B 
    } 
    return std::string(); // C 
} 

So wie ich es sehe, Fälle A und B eine direkte Konstruktion auf dem Rückgabewert auszuführen, so kopiert elision keine Bedeutung hat hier, während Fall C nicht Kopie elision durchführen kann, weil es mehrere Rückwege. Sind diese Annahmen korrekt??

Auch würde ich gerne wissen, ob

  • gibt es einen besseren Weg, um die oben schreiben (zB hat ein std::string retval; und zurück immer, dass ein oder Fall A und B als return string("1") usw. schreiben)
  • Es gibt irgendeine Bewegung, zum Beispiel "1" ist ein temporäres, aber ich nehme an, dass es als ein Parameter für den Konstruktor von std::string
  • verwendet wird, gibt es Optimierungsinteressen, die ich weggelassen habe (zB glaube ich, dass C alsgeschrieben werden könnte, wäre das eine bessere Wahl?)
+0

Warum denken Sie, Fall A von Fall C. Eine andere ist effektiv 'std :: string ("1")' und C 'std :: string ("")' –

+0

@KerrekSB Nichts –

+0

@EdHeal ich für Fall C glauben als äquivalent zu 'std :: string („1“)' Kopie elision hat es geschehen oder es keinen Unterschied aus direkt in den Rückgabewert konstruieren? Oder sind die verschiedenen Rückwegpfade mit der Kopie Elision? Wie auch immer, das ist, was ich frage mich also nicht fragen –

Antwort

3

Um es NRVO-freundlich zu machen, sollten Sie immer das gleiche Objekt zurückgeben. Der Wert des Objekts kann unterschiedlich sein, aber das Objekt sollte identisch sein.

Die obige Regel macht jedoch das Programm schwerer lesbar, und oft sollte man sich für eine bessere Lesbarkeit entscheiden als für eine unbemerkte Leistungsverbesserung. Da std::string einen Bewegungskonstruktor definiert hat, wäre der Unterschied zwischen dem Bewegen eines Zeigers und einer Länge und nicht so klein, dass ich keine Möglichkeit sehe, dies tatsächlich in der Anwendung zu bemerken.

Wie für Ihre letzte Frage, return std::string() und return {} wäre genau das gleiche.

Es gibt auch einige falsche Aussagen in Ihrer Frage. Zum Beispiel ist "1" keine temporäre. Es ist ein String-Literal. Temporär wird aus diesem Literal erstellt.

Last, but not least, obligatorisch C++ 17 Kopie Elision gilt hier nicht. Es ist für die Fälle reserviert wie

std::string x = "X"; 

, die vor der zwingenden Voraussetzung Code erzeugen könnten eine temporäres std::string und initialisieren x mit Kopie (oder verschieben) Konstruktor zu erstellen.

1

In allen Fällen kann die Kopie entfernt werden oder nicht. Bedenken Sie:

std::string j = nameof(whatever); 

Diese eine von zwei Arten umgesetzt werden könnten:

  1. Nur ein std::string Objekt, das jemals gebaut wird, j. (Die Kopie wird gelöscht.)

  2. Ein temporäres Objekt std::string wird erstellt, sein Wert wird in j kopiert, dann wird das temporäre Objekt zerstört. (Die Funktion gibt ein temporäres Objekt zurück, das kopiert wird.

    )