Warum = einen primitiven Typ in C ++ initialisieren?

8

Wo ich arbeite, denken die meisten Leute, dass Objekte am besten mit C ++ - Stil (mit Klammern) initialisiert werden, während primitive Typen mit dem = Operator initialisiert werden sollten:

%Vor%

Niemand scheint in der Lage zu sein zu erklären, warum sie die Dinge auf diese Weise bevorzugen. Ich kann sehen, dass std::string = "Foo"; ineffizient wäre, weil es eine zusätzliche Kopie beinhalten würde, aber was ist falsch daran, den = -Operator ganz einfach zu verbannen und Klammern überall zu verwenden?

Ist es eine gemeinsame Konvention? Was ist der Gedanke dahinter?

    
Tommy Herbert 09.12.2008, 17:52
quelle

9 Antworten

4

Wenn Sie nicht bewiesen haben, dass es in Bezug auf die Leistung wichtig ist, würde ich mir keine Sorgen um eine zusätzliche Kopie machen, die den Zuweisungsoperator in Ihrem Beispiel verwendet ( std::string foo = "Foo"; ). Ich wäre ziemlich überrascht, wenn diese Kopie sogar existiert, sobald Sie sich den optimierten Code ansehen, ich glaube, dass er den entsprechenden parametrisierten Konstruktor aufrufen wird.

Als Antwort auf Ihre Frage, ja, würde ich sagen, dass es eine ziemlich übliche Konvention ist. Klassischerweise haben Personen die Zuweisung verwendet, um integrierte Typen zu initialisieren, und es gibt keinen zwingenden Grund, die Tradition zu ändern. Lesbarkeit und Angewohnheit sind vollkommen gültige Gründe für diese Konvention angesichts der geringen Auswirkung auf den ultimativen Code.

    
Greg D 09.12.2008, 17:59
quelle
17

Das Initialisieren von Variablen mit dem = -Operator oder mit einem Konstruktoraufruf ist semantisch gleich, es ist nur eine Frage des Stils. Ich bevorzuge den Operator =, da er natürlicher liest.

Die Verwendung des = Operators normalerweise erzeugt keine zusätzliche Kopie - es ruft nur den normalen Konstruktor auf. Beachten Sie jedoch, dass dies bei nicht-primitiven Typen nur für Initialisierungen gilt, die gleichzeitig mit den Deklarationen stattfinden. Vergleichen Sie:

%Vor%

Wenn Sie nicht-triviale Standardkonstruktoren haben, kann die letztere Konstruktion etwas ineffizienter sein.

Der C ++ - Standard , Abschnitt 8.5, Absatz 14 besagt:

  

Andernfalls (d. h. für die verbleibenden Fälle der Kopierinitialisierung) wird ein temporäres erstellt. Benutzerdefinierte Konvertierungssequenzen, die vom Quelltyp in den Zieltyp oder eine davon abgeleitete Klasse konvertieren können, werden aufgelistet (13.3.1.4), und der beste wird durch die Überladungsauflösung (13.3) ausgewählt. Die so ausgewählte benutzerdefinierte Konvertierung wird aufgerufen, um den Initialisierungsausdruck in ein temporäres Format umzuwandeln, dessen Typ der Typ ist, der vom Aufruf der benutzerdefinierten Konvertierungsfunktion mit den cv-Qualifikationsmerkmalen zurückgegeben wird   vom Zieltyp. Wenn die Konvertierung nicht durchgeführt werden kann oder mehrdeutig ist, ist die Initialisierung fehlerhaft. Das initialisierte Objekt wird dann direkt initialisiert   aus dem temporären nach den obigen Regeln. 87 ) In bestimmten Fällen ist es einer Implementierung erlaubt, das temporäre Objekt zu eliminieren, indem das Objekt direkt initialisiert wird; siehe 12.2.

Ein Teil von Abschnitt 12.2 besagt:

  

Selbst wenn die Erstellung des temporären Objekts vermieden wird, müssen alle semantischen Einschränkungen respektiert werden, so als ob das temporäre Objekt erstellt wurde. [Beispiel:   Selbst wenn der Kopierkonstruktor nicht aufgerufen wird, müssen alle semantischen Einschränkungen, wie z. B. accessibility (11), erfüllt sein. ]

    
Adam Rosenfield 09.12.2008 17:57
quelle
11

Ich hatte gerade das Bedürfnis nach einem weiteren albernen Litb Post.

%Vor%

heißt copy-initialization , denn was der Compiler tut, wenn er keine Provisorien kennt, ist:

%Vor%

neben der Überprüfung, dass der verwendete Konvertierungskonstruktor implizit ist. Tatsächlich sind alle impliziten Konvertierungen durch den Standard in Bezug auf die Kopierinitialisierung definiert. Es wird gesagt, dass eine implizite Umwandlung von Typ U zu Typ T gültig ist, wenn

%Vor%

ist gültig.

Im Gegensatz dazu

%Vor%

macht genau das, was geschrieben wird und heißt direkte Initialisierung . Es funktioniert auch mit expliziten Konstruktoren.

Übrigens können Sie das Entfernen von temporären Objekten mit -fno-elide-constructors deaktivieren:

%Vor%

Der Standard sagt, es gibt praktisch keinen Unterschied zwischen

%Vor%

und

%Vor%

wenn T und der Typ von u primitive Typen sind. Sie können also beide Formulare verwenden. Ich denke, dass es einfach der Stil ist, der Menschen dazu bringt, die erste Form zu benutzen, anstatt die zweite.

Einige Leute verwenden vielleicht die erste in einer bestimmten Situation, weil sie die Deklaration aufklären wollen:

%Vor%

migh guckt auf jemanden als Definition einer Variablen u , die mit einem temporären Typ v initialisiert wird, der einen Parameter für seinen Konstruktor namens a erhält. Aber was der Compiler damit macht, ist folgendes:

%Vor%

Er erstellt eine Funktionsdeklaration, die ein Argument vom Typ v und einen Parameter namens a verwendet. So machen Leute

%Vor%

um das zu verdeutlichen, obwohl sie es hätten tun können

%Vor%

auch, weil es keine runden Klammern um Funktionsparameter gibt, würde der Compiler sie als eine Variablendefinition anstelle einer Funktionsdeklaration auch lesen:)

    
Johannes Schaub - litb 09.12.2008 18:21
quelle
2

Sie werden wahrscheinlich diesen Code wie

finden %Vor%

verhindert, dass eine zusätzliche Kopie erstellt wird, und kompiliert denselben Code (einen Aufruf eines Konstruktors mit einem Argument) wie der mit Klammern.

Andererseits gibt es Fälle, in denen Klammern verwenden muss, z. B. eine Konstruktormitgliedsinitialisierungsliste.

Ich denke, die Verwendung von = oder Klammern zur Konstruktion lokaler Variablen ist weitgehend eine Frage der persönlichen Wahl.

    
Greg Hewgill 09.12.2008 17:57
quelle
1

Nun, wer weiß, was sie denken, aber ich bevorzuge auch das = für primitive Typen, hauptsächlich weil sie keine Objekte sind, und weil das der "übliche" Weg ist, sie zu initialisieren.

>     
hasen 09.12.2008 17:58
quelle
0

Es ist ein Problem des Stils. Selbst die Aussage, dass "std :: string=" Foo "ineffizient wäre, weil es eine zusätzliche Kopie beinhalten würde, ist nicht korrekt. Diese "Extra-Kopie" wird vom Compiler entfernt.

    
Andrew Stein 09.12.2008 17:57
quelle
0

Ich glaube, das ist eher eine Angewohnheit, sehr wenige Objekte könnten mit = initialisiert werden, die Zeichenfolge ist eine davon. Es ist auch eine Art zu tun, was Sie sagten "überall Klammern verwenden (dass die Sprache Ihnen erlaubt, es zu benutzen)"

    
09.12.2008 17:59
quelle
0

Ein Argument, für das man sich einsetzen könnte:

std :: string foo ("bar");

Ist, dass es die gleichen Dinge behält, selbst wenn sich die Anzahl der Argumente ändert, d. h .:

std :: string foo ("bar", 5);

Funktioniert nicht mit einem '=' Zeichen.

Eine andere Sache ist, dass sich für viele Objekte ein '=' unnatürlich anfühlt, zum Beispiel sagen Sie, dass Sie eine Array-Klasse haben, wo das Argument die Länge angibt:

Array arr = 5;

Fühlt sich nicht gut an, da wir kein Array mit dem Wert 5, sondern mit der Länge 5 konstruieren:

Array arr (5);

fühlt sich natürlicher an, da Sie ein Objekt mit dem angegebenen Parameter konstruieren und nicht nur einen Wert kopieren.

    
Grumbel 09.12.2008 18:36
quelle
0

Aber nur um Sie noch mehr zu verwirren initialisieren Sie Primitive in der Initialisierungsliste mit der Objektsyntax.

%Vor%     
Martin Beckett 09.12.2008 18:44
quelle

Tags und Links