new mit Initialisierung

Beim letzten Mal wurde mit dem new-Operator nur der Standardkonstruktor der betreffenden Klasse aufgerufen. Das ist in manchen Situationen etwas wenig...

Video

Quellcode

Einzelnes Objekt mit Non-Standard-Konstruktor

#include <iostream>

class Greeter
{
public:
  Greeter()
  {
    std::cout << "Greeter initialisiert\n";
  }

  Greeter(int x)
  {
    std::cout << "Greeter mit " << x << " initialisiert\n";
  }
  
  ~Greeter()
  {
    std::cout << "Greeter zerstört\n";
  }
};

int main()
{
  Greeter *g = new Greeter(5);
  std::cout << "Hier bin ich\n";
  delete g;
}

Array-new mit Initialisierung

#include <iostream>

class Greeter
{
public:
  Greeter()
  {
    std::cout << "Greeter initialisiert\n";
  }

  Greeter(int x)
  {
    std::cout << "Greeter mit " << x << " initialisiert\n";
  }
  
  ~Greeter()
  {
    std::cout << "Greeter zerstört\n";
  }
};

int main()
{
  Greeter *gs = new Greeter[3] {Greeter(2), Greeter(5), Greeter(1) };
  std::cout << "Greeter sind vorhanden\n";
  delete[] gs;
  std::cout << "Programmende\n";
}

Erklärung

Im Grunde keine Überraschung: für den einfachen Fall mit einem Einzelobjekt (der zugegebenermaßen auch der deutlich häufigere ist), sieht das ganze genauso aus, wie man es erwarten würde. Hinter dem Typen werden einfach in Form einer Parameterliste die notwendigen Daten zur Initialisierung angegeben und der Compiler setzt das dann in den geeigneten Konstruktoraufruf um.

Etwas komplexer wird es schon beim Array-new. C++98 und C++03 bieten hier keine Möglichkeiten zur Angabe von anderen Konstruktoren an. Es können also nur Typen in Arrays verpackt werden, die  standardkonstruierbar sind. Ein gängiger Workaround für diese Art von Problem ist eine Initialisierungsfunktion, die dann in etwa so verwendet wird:

Typ *t = new Typ[10];
for (int i=0; i < 10; ++i) {
  t[i].init(parameter1, parameter2);
}

Nachteil hier natürlich: wenn man bspw. ein API zur externen Nutzung baut, dann kann man sich nie sicher sein, dass der Aufrufer auch wirklich an die init-Funktion denkt.

C++11 geht hier einen Schritt weiter und bietet eine Syntax an, mit der man auch Array-Elemente passend initialisieren kann: die Initialisierungsliste, wie im zweiten Listing dargestellt. So, wie sie in der Liste auftauchen, werden die Array-Elemente initialisiert. Das Thema "Initialisierungslisten" in C++ ist eigentlich noch wesentlich größer. Dazu aber später noch ein Video. Einziger Nachteil der Initialisierungsliste: sie kann keine dynamische Länge haben. Wenn man also dynamische Arrays initialisiert, dann wird's wieder schwieriger. Dann lugt die init-Funktion wieder um die Ecke...