wake-up-neo.com

Was bedeutet die Anweisung "return {}" in C ++ 11?

Was macht die Aussage

return {};

in C++ 11 angeben, und wann es anstelle von (say) verwendet werden soll

return NULL;

oder

return nullptr;
110
Pedia

return {}; Gibt an, dass ein Objekt des Rückgabetyps der Funktion mit einem leeren Listeninitialisierer initialisiert wurde. Das genaue Verhalten hängt vom Typ des zurückgegebenen Objekts ab.

Von cppreference.com (da das OP mit C++ 11 gekennzeichnet ist, habe ich die Regeln in C++ 14 und C++ 17 ausgeschlossen; weitere Details finden Sie unter dem Link):

  • Wenn die Klammer-Init-Liste leer ist und T ein Klassentyp mit einem Standardkonstruktor ist, wird eine Wertinitialisierung durchgeführt.
  • Wenn T ein Aggregattyp ist, wird andernfalls eine Aggregatinitialisierung durchgeführt.
  • Andernfalls wird, wenn T eine Spezialisierung von std :: initializer_list ist, das T-Objekt je nach Kontext direkt aus der geschweiften Init-Liste initialisiert oder kopiert.
  • Ansonsten werden die Konstruktoren von T in zwei Phasen betrachtet:

    • Alle Konstruktoren, die std :: initializer_list als einziges Argument oder als erstes Argument verwenden, wenn die übrigen Argumente Standardwerte haben, werden geprüft und durch Überladungsauflösung mit einem einzelnen Argument vom Typ std :: initializer_list abgeglichen
    • Wenn die vorherige Stufe keine Übereinstimmung ergibt, nehmen alle Konstruktoren von T an der Überladungsauflösung gegen die Menge der Argumente teil, die aus den Elementen der Klammer-Init-Liste bestehen, mit der Einschränkung, dass nur nicht einschränkende Konvertierungen zulässig sind. Wenn in dieser Phase ein expliziter Konstruktor als beste Übereinstimmung für eine Kopierlisteninitialisierung erstellt wird, schlägt die Kompilierung fehl (beachten Sie, dass bei einer einfachen Kopierinitialisierung explizite Konstruktoren überhaupt nicht berücksichtigt werden).
  • Andernfalls (wenn T kein Klassentyp ist), wenn die Klammer-Init-Liste nur ein Element enthält und entweder T kein Referenztyp oder ein Referenztyp ist, der mit dem Typ des Elements kompatibel ist, ist T direkt initialisiert (bei direkter Listeninitialisierung) oder kopierinitialisiert (bei Kopierlisteninitialisierung), mit der Ausnahme, dass einschränkende Konvertierungen nicht zulässig sind.

  • Andernfalls, wenn T ein Referenztyp ist, der nicht mit dem Typ des Elements kompatibel ist. (Dies schlägt fehl, wenn die Referenz eine nicht konstante Wertreferenz ist.)
  • Wenn die geschweifte Init-Liste keine Elemente enthält, wird T mit einem Wert initialisiert.

Vor C++ 11 hätten Sie für eine Funktion, die einen std::string Zurückgibt, geschrieben:

std::string get_string() {
    return std::string();
}

Wenn Sie die geschweifte Klammer in C++ 11 verwenden, müssen Sie den Typ nicht wiederholen:

std::string get_string() {
    return {}; // an empty string is returned
}

return NULL Und return nullptr Sollten verwendet werden, wenn die Funktion einen Zeigertyp zurückgibt:

any_type* get_pointer() {
    return nullptr;
}

NULL ist jedoch seit C++ 11 veraltet, da es nur ein Alias ​​für einen ganzzahligen Wert (0) ist, während nullptr ein echter Zeigertyp ist:

int get_int() {
    return NULL; // will compile, NULL is an integer
}

int get_int() {
    return nullptr; // error: nullptr is not an integer
}
100
wasthishelpful

Das ist wahrscheinlich verwirrend:

int foo()
{
  return {};   // honestly, just return 0 - it's clearer
}

Dies ist wahrscheinlich nicht:

SomeObjectWithADefaultConstructor foo()
{
  return {};
  // equivalent to return SomeObjectWithADefaultConstructor {};
}
89
Richard Hodges

return {}; Bedeutet, dass {} Der Initialisierer für den Rückgabewert ist . Der Rückgabewert wird mit einer leeren Liste listeninitialisiert.


Hier einige Hintergrundinformationen zum Rückgabewert , basierend auf [stmt.return] im C++ Standard:

Für eine Funktion, die nach Wert zurückgibt (dh der Rückgabetyp ist keine Referenz und nicht void), gibt es ein temporäres Objekt mit dem Namen als Rückgabewert . Dieses Objekt wird durch die Anweisung return erstellt, und die Initialisierungen hängen von den Angaben in der return-Anweisung ab.

Der Rückgabewert bleibt bis zum Ende des vollständigen Ausdrucks im Code erhalten, der die Funktion aufgerufen hat. Wenn es einen Klassentyp hat, wird sein Destruktor ausgeführt, es sei denn, der Aufrufer bindet einen Verweis direkt an ihn.

Der Rückgabewert kann auf zwei verschiedene Arten initialisiert werden:


Angenommen, T ist der Rückgabetyp der Funktion. Beachten Sie dann, dass return T{}; Sich von return {} Unterscheidet: Im ersten Fall wird ein temporärer T{} Erstellt, und dann der Der Rückgabewert wird von diesem temporären Wert kopiert.

Dies kann nicht kompiliert werden, wenn T keinen zugänglichen Kopier-/Verschiebekonstruktor hat, aber return {}; Erfolgreich ist, selbst wenn diese Konstruktoren nicht vorhanden sind. Dementsprechend kann return T{}; Nebenwirkungen des Kopierkonstruktors usw. anzeigen, obwohl dies ein Kopierentscheidungskontext ist, so dass dies möglicherweise nicht der Fall ist.


Hier ist eine kurze Zusammenfassung der Listeninitialisierung in C++ 14 (N4140 [dcl.init.list]/3), wobei der Initialisierer leer ist Liste:

  • Wenn T ein Aggregat ist, wird jedes Element von seinem Klammer- oder Gleichheitsinitialisierer initialisiert, falls es einen hatte, andernfalls als wenn durch {} (so wenden Sie diese Schritte rekursiv an).
  • Wenn T ein Klassentyp mit einem benutzerdefinierten Standardkonstruktor ist, wird dieser Konstruktor aufgerufen.
  • Wenn T ein Klassentyp mit einem implizit definierten oder mit = default Definierten Standardkonstruktor ist, lautet das Objekt null-initialisiert und der Standardkonstruktor wird aufgerufen.
  • Wenn T ein std::initializer_list Ist, ist der Rückgabewert eine leere solche Liste.
  • Andernfalls (d. H. T ist ein Nichtklassentyp - Rückgabetypen können keine Arrays sein) wird der Rückgabewert mit Null initialisiert.
26
M.M

Es ist eine Art Kurzform für eine neue Instanz des Rückgabetyps für Methoden.

3
Victor Mwenda