[C++11] Uniform initialization - doch nicht so uniform?

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

[C++11] Uniform initialization - doch nicht so uniform?

Beitrag von fat-lobyte » Fr Mär 02, 2012 11:01 am

Hallo!
Ich möchte nur kurz von meinen Erfahrungen berichten.
Im neuen Standard gibt es einige Änderungen, wie man Objekte und Basisklassen initialisiert.

Wozu ist das überhaupt notwendig?

Betrachtet folgenden Code:

Code: Alles auswählen

rectangle        w (origin(), extents());
complex<double>  c (2.71828, 3.14159);
int              a[] = {1, 2, 3, ,4};
vector           v; for(int i;i<=4;++i) v.push_back(i);
Alle dieser vier Zeilen dienen der *Absicht* ein Objekt zu deklarieren und zu initialisieren. Diese sehen aber unterschiedlich aus, und bei Vektor muss man sogar Code für die initialisierung bereitstellen. Warum sage ich "Absicht"? ÜBERRASCHUNG!! Die erste Zeile, die zwar aussieht wie eine Variablendeklaration ist eine Funktionsdefinition!

Na gut,
da hat sich was getan in C++11:

Code: Alles auswählen

rectangle        w {origin(), extents()};
complex<double>  c { 2.71828, 3.14159  };
int              a[] {1, 2, 3, ,4};
vector           v   {1, 2, 3, ,4};
Sieht doch hübsch aus, alles einheitlich, oder? Die erste Zeile ist jetzt übrigens tatsächlich eine Variablendeklaration.

Das ganze funktioniert sogar in Konstruktoren:

Code: Alles auswählen

struct ABase {
    ABase(int x) : _x{x} { }    
private:
    int _x;
};

struct A : public ABase {
    A (double f) : ABase{42}, _f{f}
private:
    double _f;
};
Und es verhindert die "Verschmälerung" (narrowing), Beispielsweise von integer und floating point datentypen:

Code: Alles auswählen

int x0= 7.3;	// ok: aber daten gehen verloren!
int x1 {7.3};	// error: narrowing
Dabei ist es übrigens völlig egal, ob zwischen den geschweiften Klammern und dem Variablennamen ein "=" steht oder nicht.

Bis jetzt alles schön und gut. Ich bin ein großer Fan.
Es wird sogar empfohlen *alle* initialisierungen auf diese Syntax umzustellen.

Das habe ich gemacht, und siehe da: zwei Problemchen:
1) Referenzen!

Code: Alles auswählen

struct A{};

int main()
{
    A a;
    A& a_ref{a}; // BUMM!!
}
Wieso auf einmal? Tja, hier wird aus {a} erstmal ein temporäres Objekt des Typs A erstellt, und mit a initialisiert. Dieses temp. Objekt wäre dann RValue und müsste mit einer nicht konstanten Referenz verknüpft werden. Das macht keinen Sinn: was ist eine Referenz auf ein Temporäres Objekt?
Seltsame Sache ist das, aber leider ist das so, also muss man hier weiterhin a_ref() schreiben.

2) Wenn der Konstruktor eine intializer_list akzeptieren würde!
Die folgenden zwei Zeilen haben nicht den gleichen Effekt!!

Code: Alles auswählen

std::vector<int> v(100);
std::vector<int> v{100};
Wieso nicht? Nun, das betrifft zwei Konstruktoren des vector's:

Code: Alles auswählen

explicit vector(size_type n); // 1
vector(initializer_list<T>, const Allocator& = Allocator()); // 2
Die erste Zeile ruft den ersten konstruktor auf, es wird ein vektor mit 100 Elementen erstellt.
Die zweite Zeile erstellt aber ein objekt vom Typ std::initializer_list<int>, mit einem Element, nämlich 100 -> der zweite Konstruktor wird aufgerufen.

Wäre der zweite konstruktor nicht vorhanden, wären die beiden aufrufe das gleiche, denn dann wäre die initializer_list kein gültiges Argument für den ersten konstruktor, somit kann mit dem 100 nur ein size_t gemeint sein.

Tja, das finde ich persönlich wirklich unschön aber auch damit muss ich Leben.

Nichtsdestotrotz!
Ich finde die Initialisierung ist ne coole Sache, und ich werde sie trotz der Probleme so weit wie möglich verwenden. Die zwei Problemstellen muss man sich halt merken.
Gehet hin und verkündet die frohe Botschaft!

ps.: Wenn jemand weitere Probleme findet, bitte bitte postet sie hier.
Wenn ich welche finde mache ich das selbstverständlich auch.
Haters gonna hate, potatoes gonna potate.

Panke
Beiträge: 70
Registriert: So Nov 14, 2010 10:47 am

Re: [C++11] Uniform initialization - doch nicht so uniform?

Beitrag von Panke » Fr Mär 02, 2012 2:56 pm

Ich sehe die Verwechselungsgefahr bei der Initialisierung des vectors auch. Aber im Grunde sind es auch zwei leicht verschiedene Dinge. In () stehen Argumente des Konstruktors, in {} Inhalte des vectors.

Dass man die Inhalte von Containern direkt angeben kann, war auch lange überfällig.

Antworten