Wenn tun ich haben zu verwenden Initialisierer Listen bei der Initialisierung von C++ - Klassen-Mitglieder?

StackOverflow https://stackoverflow.com/questions/1632484

  •  06-07-2019
  •  | 
  •  

Frage

sagen wir, ich habe std::map< std::string, std::string > m_someMap als eine private member-variable der Klasse A

Zwei Fragen:(und der einzige Grund, warum ich Frage, ist, weil ich stieß code ähnlich)

  1. Was ist der Zweck dieser Zeile:

    A::A() : m_someMap()
    

    Jetzt weiß ich, dass dies Initialisierung, aber Sie müssen dies tun, wie, dass?Ich bin verwirrt.

  2. Was ist der Standard-Wert std::map< std::string, std::string > m_someMap, auch C# definiert, int, double, etc.immer initialisiert defualt 0 und Objekte sind auf null (zumindest in den meisten Fällen) Also, was ist die Regel in C++??sind Objekt initialisiert durch defualt auf null und primitive garbage?Natürlich nehme ich über die Instanz-Variablen.

EDIT:

auch, da die meisten Menschen darauf hingewiesen, dass dies ist ein Stil, der Wahl und nicht notwendig, was ist:

A::A() :m_someMap(), m_someint(0), m_somebool(false)

War es hilfreich?

Lösung

m_somemap

  1. Sie müssen nicht müssen.
  2. Was Sie bekommen, wenn Sie es weglassen. Ein leeres std::map< std::string, std::string >, das heißt, eine gültige Instanz dieser Karte, die keine Elemente in sich hat

m_somebool

  1. Sie haben es zu initialisieren, um true oder false, wenn Sie es einen bekannten Wert haben wollen. Boolesche Werte sind „einfache alte Datentypen“, und sie haben nicht das Konzept eines Konstruktor. Darüber hinaus ist die C ++ Sprache keine Standardwerte für nicht explizit initialisiert booleans angeben.
  2. Was Sie bekommen, wenn Sie es weglassen: ein boolean Mitglied mit einem nicht spezifizierten Wert. Sie müssen dies nicht tun und später seinen Wert verwenden. Aus diesem Grunde ist es eine dringend empfohlene Richtlinie, die Sie alle Werte dieses Typs initialisieren.

m_someint

  1. Sie haben es bis zu einem gewissen ganzzahligen Wert zu initialisieren, wenn Sie es einen bekannten Wert haben wollen. Die ganzen Zahlen sind „einfache alte Datentypen“, und sie haben nicht das Konzept eines Konstruktor. Darüber hinaus gibt die Programmiersprache C ++ Standard keine Werte für nicht explizit initialisiert ganze Zahlen.
  2. Was Sie bekommen, wenn Sie es weglassen: ein int Element mit einem nicht spezifizierten Wert. Sie müssen dies nicht tun und später seinen Wert verwenden. Aus diesem Grunde ist es eine dringend empfohlene Richtlinie, die Sie alle Werte dieses Typs initialisieren.

Andere Tipps

Es gibt keine Notwendigkeit, es wirklich tun.
Der Standardkonstruktor wird es autmatically tun.

Aber somtimes indem sie sie explizit macht es fungiert als eine Art Dokumentation:

class X
{
    std::map<string,string>  data;
    Y                        somePropertyOfdata;

    X()
      :data()                    // Technically not needed
      ,somePropertyOfdata(data)  // But it documents that data is finished construction
    {}                           // before it is used here.
};

Die Regel in C ++ ist, dass wenn Sie nicht ausdrücklich POD Daten initialisieren es nicht definiert ist, während andere Klassen haben dort Standardkonstruktors automatisch aufgerufen (auch wenn nicht explizit so vom Programmierer durchgeführt).

Aber zu sagen, dass. Bedenken Sie:

template<typename T>
class Z
{
     T  data;   
     Z()
        :data()    // Technicall not need as default constructor will
                   // always be called for classes.
                   // But doing this will initialize POD data correctly
                   // if T is a basic POD type. 
     {}
};

Hier würden Sie Daten exepect Standard initialisiert werden.
Technisch POD haben keine Konstruktoren also, wenn T int war dann würden Sie erwarten, dass es etwas zu tun? Becuase es explizit auf 0 oder das Äquivalent für POD-Typen eingestellt initialisieren wurde.

Für das Bearbeiten:

class A
{
    std::map<string,string>   m_someMap;
    int                       m_someint;
    bool                      m_somebool;
   public:
    A::A()
       : m_someMap()      // Class will always be initialised (so optional)
       , m_someint(0)     // without this POD will be undefined
       , m_somebool(false)// without this POD will be undefined
    {}
};

Wie andere darauf hingewiesen: Es ist nicht notwendig, aber mehr oder weniger eine Frage des Stils. Der Vorteil: es zeigt, dass Sie explizit den Standard-Konstruktor verwenden möchten, und macht den Code ausführlicher. Der Nachteil:. Wenn Sie mehr als ein Ctor haben kann es ein Schmerz sein, Änderungen in alle von ihnen zu halten und manchmal Sie die Teilnehmer hinzuzufügen und zu vergessen, sie zu der ctors Initialisiererliste hinzuzufügen und es widersprüchlich aussehen

A::A() : m_someMap()

Diese Linie ist in diesem Fall nicht notwendig. Allerdings im allgemeinen , es ist der einzige richtige Weg, die Teilnehmer zu initialisieren.

Wenn Sie einen Konstruktor wie folgt aus:

X() : y(z) {
 w = 42;
}

dann geschieht folgendes, wenn der X Konstruktor aufgerufen wird:

  • Zunächst werden alle Mitglieder initialisiert: für y, wir ausdrücklich sagen, wir wollen den Konstruktor nennen, die eine z als Argument. Für w, hängt von der Art der w was passiert. Wenn w ein POD-Typ ist (das heißt, im Grunde ein C-kompatiblen Typ: keine Vererbung, keine Konstruktoren oder Destruktoren, alle Mitglieder der Öffentlichkeit, und alle Mitglieder sind POD-Typen als auch), dann ist es nicht initialisiert. Sein Anfangswert ist, was Müll wurde an dieser Speicheradresse gefunden. Wenn w ein nicht-POD-Typ ist, dann wird der Standard Konstruktor aufgerufen (nicht-POD-Typen sind immer auf dem Bau initialisiert).
  • Sobald beide Mitglieder konstruiert worden, we und rufen Sie den Zuweisungsoperator 42 zuweisen w.

Die wichtige Sache zu beachten ist, dass alle Konstrukteure genannt werden vor wir den Körper des Konstruktors ein. Sobald wir im Körper sind, dann haben alle Mitglieder bereits initialisiert wurde. So gibt es zwei mögliche Probleme mit unserem Konstruktorrumpf.

  • Was passiert, wenn w von einem Typ ist, der nicht über einen Standardkonstruktor hat? Dann wird dies nicht kompilieren. Dann ist es muss explizit nach dem : initialisiert werden, wie y ist.
  • Was passiert, wenn diese Folge von Aufrufen beide default Konstruktor und Zuweisungsoperator ist unnötig langsam? Vielleicht wäre es viel effizienter sein, einfach den richtigen Konstruktor aufzurufen zu beginnen.

Also kurz gesagt, da m_someMap ein nicht-POD-Typ ist, haben wir nicht streng Notwendigkeit sprechen : m_someMap() zu tun. Es wäre ohnehin Standard gebaut. Aber wenn es ein POD-Typ gewesen war, oder wenn wir ein anderen Konstruktor als der Standard nennen wollten, dann hätten wir benötigt, um dies zu tun.

Just klar sein über das, was (in Bezug auf Ihre zweite Frage) geschieht

std::map< std::string, std::string > m_someMap erzeugt einen Stapel Variable namens m_someMap und der Standard-Konstruktor wird sie aufgefordert hatte. Die Regel für C ++ für alle Ihre Objekte ist, wenn Sie gehen:

T varName;

wobei T ein Typ ist, varName ist standardmäßig aufgebaut.

T* varName;

sollte explizit auf NULL zugewiesen werden (oder 0) -. Oder nullptr im neuen Standard

Um den Standardwert Frage zu klären:

C ++ nicht über das Konzept von einigen Typen implizit durch Verweis zu sein. Es sei denn, etwas explizit als Zeiger deklariert wird, ist es nicht je einen Wert von Null annehmen. Dies bedeutet, dass alle Klasse einen Standardkonstruktor für den Aufbau der Anfangswert haben wird, wenn keine Konstruktor Parameter angegeben werden. Wenn kein Standard-Konstruktor deklariert wird, wird der Compiler für Sie generiert. Auch, wenn eine Klasse enthält Elemente, die von klassifizierten Typen sind, werden diese Mitglieder implizit über ihre eigenen Standardkonstruktoren bei Objektbau initialisiert werden, es sei denn, Sie verwenden, um die Doppelpunkt-Syntax, um explizit einen anderen Konstruktor aufrufen.

Es passiert einfach so, dass der Standard-Konstruktor für alle STL-Container-Typen einen leeren Behälter aufbaut. Andere Klassen können andere Konventionen für das, was ihre Standardkonstruktoren tun, so dass Sie wollen immer noch bewusst sein, dass sie in Situationen wie diese aufgerufen wird. Deshalb ist die A::A() : m_someMap() Linie, die wirklich nur den Compiler zu sagen zu tun, was es tun würde sowieso schon.

Wenn Sie ein Objekt in C++ Konstruktor durchläuft die folgende Reihenfolge:

  1. Rufen Sie die Konstruktoren aller übergeordneten virtuellen Unterricht in der gesamten Klasse Baum (In beliebiger Reihenfolge)
  2. Rufen Sie die Konstruktoren direkt vererbt übergeordneten Klassen in der Reihenfolge der Deklaration
  3. Rufen Sie die Konstruktoren aller member-Variablen in der Reihenfolge der Deklaration

Es gibt ein paar mehr Besonderheiten, als diese, und einige Compiler erlauben, Sie zu zwingen, ein paar Dinge aus dieser bestimmten Reihenfolge, aber das ist die Allgemeine Idee.Für jede dieser Konstruktor ruft Sie festlegen können, dass die Argumente im Konstruktor, in dem Fall wird C++ rufen Sie den Konstruktor wie angegeben, oder lassen Sie es allein und C++ werden versuchen, um die Standard-Konstruktor.Der default-Konstruktor ist einfach der, der nimmt keine Argumente an.

Wenn Ihre virtuelle parent-Klassen, nicht-virtuellen übergeordneten Klassen oder member-Variablen, die nicht über ein Standard-Konstruktor, oder müssen geschaffen werden, mit etwas anderem als der Standard, fügen Sie Sie der Liste der Konstruktor ruft.Da C++ setzt eine Standard-Konstruktor aufrufen, es gibt absolut keinen Unterschied zwischen dem setzen einer default-Konstruktor in der Liste aus und verlassen Sie sich ganz aus (C++ wird nicht (es sei denn unter besonderen Umständen auch außerhalb des Anwendungsbereichs dieser Frage) erstellen Sie ein Objekt, ohne ein Aufruf an einen Konstruktor von irgendeiner Art).Wenn eine Klasse keinen Standardkonstruktor und Sie nicht geben Sie einen Konstruktor aufrufen, der compiler wirft einen Fehler.

Wenn es um eingebaute Typen wie Z float oder int, der default-Konstruktor tut überhaupt nichts, und so die variable wird der Standard-Wert, was übrig war, in dem Stück der Erinnerung.Alle eingebauten Typen haben auch einen copy-Konstruktor, so dass Sie können Sie können, initialisieren Sie Sie durch die Weitergabe Ihrer ursprünglichen Wert, als einziges argument die variable Konstruktor.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top