[C++]structs sauber initialisieren

Herakles

Profifragensteller
Moin!

Nach Jahren der C-Programmierung muss ich mich derzeit mit einem C++-Projekt herumschlagen. Bisher habe ich es zur guten Praxis gemacht, dass ich alle Variablen initialisiere, damit keine ungewünschten Effekte auftreten. Bei Standardtypen ist das einfach:

Code:
uint16_t wurst = 0;

Bei zusammengesetzten structs mach ich das wie folgt:

Code:
struct mahlzeit {
   uint16_t wurst;
   uint8_t brot;
};

int main(void) {
   struct mahlzeit essen;
   memset( &essen, 0, sizeof(struct mahlzeit) );
   (...)
}

Vergleichbares mache ich auch, wenn ich einen Pointer habe:

Code:
int main(void) {
   struct mahlzeit *Pessen;
   Pessen = malloc(sizeof(struct mahlzeit));
   memset( Pessen, 0, sizeof(struct mahlzeit) );
   (...)
}

Nun bekomme ich in C++ damit Probleme. Zum Einen ist es dort ja so, dass Speicher mittels
Code:
struct mahlzeit *Pessen = new struct mahlzeit;

alloziert wird. Angeblich wird damit nun der Speicherbereich sowohl alloziert als auch auf "0" gesetzt (wobei ich mich gerade Frage, woher ich diese Info eigentlich habe).

Was aber, wenn ich keinen Pointer habe, sondern bspw. eine lokale Variable, die ich nicht als Pointer deklariere:

Code:
struct mahlzeit essen;

Ist dieses struct in c++ dann sofort auch sauber mit "0" initialisiert? Wenn nicht, darf ich hier ein memset(3) aufrufen? Ich habe mit memset(3) schon komische Effekte unter C++ erlebt, wo das Programm einfach stehen blieb o.Ä. Das Verhalten scheint also anders zu sein, als unter C. In einem anderen Forum
http://www.forum-3dcenter.org/vbulletin/archive/index.php/t-504728.html
habe ich gelesen, dass mit memset(3) der "vTable-Pointer mit 0 überschrieben" wird (posting von Nighthawk13). Was auch immer das ist.

Von der Initialisierung mal ganz abgesehen kann es ja durchaus auch mal vorkommen, dass man ein zuvor genutztes struct auch gern wieder zurücksetzen möchte auf "0". Auch für diesen Fall wüsste ich keine Lösung, FALLS man memset(3) nicht gefahrenfrei nutzen könnte...

Weil mir die Internetrecherche nicht hergibt, was ich will (eine klare Beantwortung meiner Frage), möchte ich mich gern an Euch Experten wenden. Könnte Ihr mir auf die Sprünge helfen?

Fragende Grüße
Herakles
 
Wieso verwendest du keine Klasse? Mit einer Klasse hast du alle Möglichkeiten eines Structs incl. eines Konstruktors der dir deine Variablen initialisiert.
c++ initialisiert ints genauso wenig selbständig wie c.

Mal angenommen du willst standardmässig die uints auf 0 initialisieren, aber auch die Möglichkeit haben direkt initialisierungswerte zu definieren, dann kannst du das so machen:

Code:
class Essen{
public:
    explicit Essen(uint wurst=0, uint brot = 0);
    uint wurst;
    uint brot;
}

Essen::Essen(uint wurst, uint brot){
this->brot = brot;
this->wurst = wurst;
};

Erzeugst du nun ein Objekt (egal ob du es auf dem Stack oder Heap erzeugst sind beiden Ints mit 0 initialisiert):
Code:
Essen erstesEssen = Essen();
Essen *pointerEssen = new Essen();

Ebenfalls kannst du die ints aber auch direkt auf einen Wert initialisieren:
Code:
Essen nocheinEssen = Essen(2,6);
Essen *nocheinPointerEssen = new Essen(4,8);

Das ist eigentlich die sauberste Art. Wenn du immer auf 0 (oder einen fixen Wert initialisierst kannst du den Konstruktor auch abkürzen)
Code:
Essen::Essen() : wurst{0}, brot{0}{
}
 
Sorry ich bin gerade auf dem Sprung, deshalb etwas kürzer.

Wenn Du kannst nutze C++11!

Dann schreibst Du:
int x{11};
Das hat einige Vorteile.

Bei auto aber immer bitte =.
auto i = 10;
und nicht
auti i{10};


Memset hat meiner Meinung nach nichts in einem "reinem" C++ Programm zu suchen.
Ein struct ist in C++ nichts anderes als eine Klasse wo alles public ist.
Du kannst Konstruktoren mit Standardwerten nutzen.
Oft reicht aber der schon vom Compiler erstellte Konstruktor aus.
Und nutze SmartPointer wie: unique_ptr und shared_ptr.

Hier kannst Du mal stöbern:
http://www.stroustrup.com/C++11FAQ.html

initializer lists
null pointer
smart pointers
auto
control of defaults: copy and move
memory model
und und und.....
 
Ich möchte Euch gern herzlich danken.

Zusätzlich habe ich noch diese Seite hier gefunden:

https://www.augias.org/paercebal/tech_doc/doc.en/cp.memset_is_evil.html

Ich werde heute also einige Stunden stöbern und kann dann sicher noch ein wenig mehr zum Thema sagen. Eine Sache ist mir (derzeit) noch etwas unklar. Man nehme an, man hat eine Klasse (oder struct oder whatever) mit über 1000 Variablen und eigentlich sollen die alle "0" sein. Den absolut unwahrscheinlichen Fall mal angenommen - müsste ich da tatsächlich jedes Element einzeln im Konstruktor auf "0" initialisieren? Da gefiel mit das C-memset dann doch besser... Aber ich nehme an, dass ich diese Frage nach meinem Studium heute Vormittag schon selbst beantworten kann.

Sobald ich mehr weiß, werde ich wieder posten! :)

Grüße
Herakles
 
Die Anzahl Variablen klingt für mich nach nem Container (welcher Art auch immer) und den kannst du ja durch ne Schleife initialisieren... (Niemand will 1000 Variablen von Hand verwalten)
 
Vector vom Typ double mit 1000 Elemente mit 0.0 initialisiert.
vector<double> iVec(1000,0.0);

Welchen STL Container man benutzt hängt von dem jeweiligen Fall ab.
 
Man nehme an, man hat eine Klasse (oder struct oder whatever) mit über 1000 Variablen und eigentlich sollen die alle "0" sein. Den absolut unwahrscheinlichen Fall mal angenommen - müsste ich da tatsächlich jedes Element einzeln im Konstruktor auf "0" initialisieren?

Nein, dann solltest du dein Programm neu schreiben ;) C++ ist eben nicht "C mit Klassen", die beiden Sprachen haben prinzipiell unterschiedliche Spezifikationen und Verhalten. Was in C geht, geht in C++ oft nicht oder tut etwas komplett anderes. Versuche also bitte nicht Probleme mit C++ in C zu lösen, das fliegt dir um die Ohren.

VTable ist das hier: http://de.wikipedia.org/wiki/Tabelle_virtueller_Methoden
 
In C++11 kann man auch
Code:
struct Foobar
{
    int a;
    double b;
    int* p;
};

Foobar foobar{};
machen, woraufhin a == 0, b == 0.0 und p == nullptr sind.
 
c++ initialisiert ints genauso wenig selbständig wie c.
Aber viele Compiler tun es eigenmächtig. Hängt eben davon ab, wie portabel der Code sein soll.
Wenn du immer auf 0 (oder einen fixen Wert initialisierst kannst du den Konstruktor auch abkürzen)
Code:
Essen::Essen() : wurst{0}, brot{0}{
}
Das ist keine Abkürzung, sondern der eigentlich richtige Weg. Die Variablen werden so initialisiert, bevor der Konstruktor aufgerufen wird. Andernfalls kann es zu Problemen kommen, wenn der Konstruktor komplex ist, vielleicht noch Unterobjekte erstellt werden etc.

@Herakles: Ich bin mir nicht sicher, ob das etwas hilft, aber es gibt eine spezielle Form des Operators "new", die keinen Speicher reserviert, sondern ein Objekt in einen schon reservierten Speicher schreibt:
Code:
int* p=new(q) int;
oder
Txy* p=new(q) Txy(a,b,c)
Dabei ist q ein Zeiger auf schon reservierten Speicher (z. B. vorher mit einem "new" reserviert). Das erste Beispiel ist ein einfacher Datentyp, das zweite eine Klasse mit Konstruktoraufruf.
 
Meine Erfahrung ist, dass neuer Speicher vom Betriebssystem genullt kommt.

Aber wenn man alten Speicher, den zwischendurch kein anderer Prozess hatte bekommt, dann stehen da die alten Daten drin. Also ist selbst ein new kein Garant genullten Speicher zu bekommen.
 
Zurück
Oben