<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Objekt-Initialisierung]]></title><description><![CDATA[<p>Ich glaub ich bin blöd. Habe etwas folgender Art geschrieben:</p>
<pre><code class="language-cpp">class Klasse1 {
    public:
      float *nummern;

      Klasse1(Klasse2 *klasse2) {
        nummern = new float[klasse2-&gt;laenge];
        for (int i = 0; i &lt; klasse2-&gt;laenge; i++) {
          nummern[i] = 1.0f;
        }
      }
}

class Klasse2 {
    public:
      int laenge;
      Klasse1 objekt;

      Klasse2(int laenge) {
        this-&gt;laenge = laenge;
        objekt = Klasse1(this);
      }
}
</code></pre>
<p>Jetzt hatte ich erwartet, dass ich in einem Objekt der Klasse2 dann auf das Unterobjekt zugreifen kann und ein float-Array voll mit 1.0 habe. Ist aber nicht. Die Inhalte werden zurückgesetzt und ich bekomme irgendwelche Unsinnszahlen raus. Wenn ich aber im Konstruktor von Klasse2 mit &quot;cout &lt;&lt; Klasse1(this).nummern[0] &lt;&lt; endl;&quot; nachschaue, dann ist da 1.0 drin. Also stimmt irgendwas mit der anschließenden Zuweisung in &quot;objekt&quot; nicht. Nur was?</p>
<p>Wenn ich objekt als Zeiger gestalte, dann geht natürlich alles. Ich frage mich aber, ob das hier (oder auch im allgemeinen Fal) sinnvoll ist, weil ich dann ja jedes Mal, wenn ich das objekt benutzen will, ein Zeiger dereferenziert werden muss. Das kann's ja nicht sein, oder?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/199485/objekt-initialisierung</link><generator>RSS for Node</generator><lastBuildDate>Sat, 03 Oct 2026 19:18:37 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/199485.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 03 Dec 2007 15:48:38 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 15:48:38 GMT]]></title><description><![CDATA[<p>Ich glaub ich bin blöd. Habe etwas folgender Art geschrieben:</p>
<pre><code class="language-cpp">class Klasse1 {
    public:
      float *nummern;

      Klasse1(Klasse2 *klasse2) {
        nummern = new float[klasse2-&gt;laenge];
        for (int i = 0; i &lt; klasse2-&gt;laenge; i++) {
          nummern[i] = 1.0f;
        }
      }
}

class Klasse2 {
    public:
      int laenge;
      Klasse1 objekt;

      Klasse2(int laenge) {
        this-&gt;laenge = laenge;
        objekt = Klasse1(this);
      }
}
</code></pre>
<p>Jetzt hatte ich erwartet, dass ich in einem Objekt der Klasse2 dann auf das Unterobjekt zugreifen kann und ein float-Array voll mit 1.0 habe. Ist aber nicht. Die Inhalte werden zurückgesetzt und ich bekomme irgendwelche Unsinnszahlen raus. Wenn ich aber im Konstruktor von Klasse2 mit &quot;cout &lt;&lt; Klasse1(this).nummern[0] &lt;&lt; endl;&quot; nachschaue, dann ist da 1.0 drin. Also stimmt irgendwas mit der anschließenden Zuweisung in &quot;objekt&quot; nicht. Nur was?</p>
<p>Wenn ich objekt als Zeiger gestalte, dann geht natürlich alles. Ich frage mich aber, ob das hier (oder auch im allgemeinen Fal) sinnvoll ist, weil ich dann ja jedes Mal, wenn ich das objekt benutzen will, ein Zeiger dereferenziert werden muss. Das kann's ja nicht sein, oder?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414317</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414317</guid><dc:creator><![CDATA[David Schneider]]></dc:creator><pubDate>Mon, 03 Dec 2007 15:48:38 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 16:14:15 GMT]]></title><description><![CDATA[<p>Also mich wundert, dass das Ganze bei dir ueberhaupt compiliert. Du hast in Klasse1 einen Konstruktor definiert, weshalb der default-Ctor ncht mehr implizit angeboten wird. Das Member &quot;objekt&quot; von Klasse2 wird aber (dank fehlender initialisierungsliste im Ctor vin Klasse2) default-initialisiert. Das sollte dir der Compiler eigentlich nicht durchgehen lassen.</p>
<p>Dann noch ein paar Einzelheiten:<br />
- Einer der Hauptpfeiler der OOP ist die Kapselung. Unter anderem bedeutet Kapselung in C++, dass man moeglichst nie Membervariablen oeffentlich zugaenglich macht. =&gt; Die Member nummern, laenge und objekt bitte als private deklarieren. Falls man dennoch Zugriff auf die member gestatten will, gibs sogenannte getter udn setter methoden.<br />
- pointer werden beim Zerstoeren des beinhaltenden Objekts nicht automatisch Zerstoert. Du hast also ein Speicherleck, sobald du ein Objekt der Klasse1 hast (und wieder zerstoerst). Schreib also moeglichst einen Destruktro zu dieser Klasse.<br />
- pointer werden 1:1 kopiert, wenn das beinhaltende Objekt per implizit generiertem operator= kopiert wird. Man endet also mit zwei Objekten, die auf den selben Speicher verweisen. Wird eins zerstoert, dann wird dessen Destruktor auch den Speicherbereich freigeben (du denkst doch hoffentlich an Speicherlecks, oder? :xmas1: ) - Resultat: das andere Objekt hat einen Pointer ins Nirvana. Die Loesung ist das Schreiben eines eigenen operator= fuer jede Klasse, die pointer als member hat. Also auch fuer Klasse1.<br />
- Verwende initialisierungslisten, wo moeglich. Damit verhinderst du unnoetige Aufrufe von operator= im konstruktorrumpf.</p>
<p>ohne jetzt weiter auf Sinn und Unsinn des allgemeinen Designs einzugehn, wuerde ich deine beiden Klassen wie folgt umschreiben:</p>
<pre><code class="language-cpp">class Klasse1 {
public: 
  Klasse1(size_t n) nummern(n, 1.0f){}
private:
  std::deque&lt;float&gt; nummern;  //keine Pointer, keine Speicherlecks, 
                              //Kopieren ist sicher, alles bestens!
};

class Klasse2 {
public:
  Klasse2(size_t laenge) : laenge(laenge), objekt(laenge) {}
private:
  size_t laenge;
  Klasse1 objekt;
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1414333</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414333</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Mon, 03 Dec 2007 16:14:15 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 16:17:02 GMT]]></title><description><![CDATA[<pre><code class="language-cpp">class bar;

class foo
{
    float* m_data;

public:
    foo(bar const&amp; bar_inst)
    : m_data(new float[bar_inst.size()](1.0f))
    {}
    ~foo() { delete [] m_data; }

    const float* data() const { return m_data; }
}

class bar 
{
    std::size_t m_size;
    foo m_foo;

public:
    bar(std::size_t size) 
    : m_size(size), m_foo(*this) 
    {}

    std::size_t size() const { return m_size; }
};
</code></pre>
<p><img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /> soooo ^^</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414334</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414334</guid><dc:creator><![CDATA[*D*Evil]]></dc:creator><pubDate>Mon, 03 Dec 2007 16:17:02 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 16:43:07 GMT]]></title><description><![CDATA[<p>zu pumuckl:</p>
<p>Ich muss zugeben, diesen desaströsen Eindruck kann man von obigem Code durchaus gewinnen. Allerdings ist er nur ein Ausschnitt. Natürlich gibt es Default-Konstruktoren, und auch einen passenden Destruktor für alle Klassen, um dynamisch allokiertes Zeugs wieder zu löschen. Deswegen wird das auch gescheit kompliliert. Außerdem sind die meisten Sachen in meinem kompletten Code auch private (zugegeben: mein Fehler, dass ich sie hier alle unter public geschrieben habe). Ich habe außerdem absichtlich auf jede Art von STL-Datenverwaltung verzichtet, weil soweit ich weiß blanke Arrays immer noch am schnellsten sind, und mir das in meinem Fall sehr wichtig ist. Daher auch die zusätzliche Frage: Ist eine Initialisierungsliste tatsächlich schneller als ein Zuweisungs-Operator im Rumpf? Ich dachte, dass sei nur eine alternative Notation, die ohnehin gleich kompliiert wird. Oder ist das gar nicht der Grund, warum du diese Aufrufe vermeiden willst?</p>
<p>Allerdings hat mich dein dritter Punkt auf eine Idee gebracht. Ich ging davon aus (weil ich sowas gelesen hatte), dass operator= in diesem Fall gar keine Zuweisung, sondern der Copy-Konstruktor ist. Ist das hier gar nicht der Fall?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414346</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414346</guid><dc:creator><![CDATA[David Schneider]]></dc:creator><pubDate>Mon, 03 Dec 2007 16:43:07 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 18:47:47 GMT]]></title><description><![CDATA[<p>Wie der Name schon sagt, ist der Zuweisungsoperator im Rumpf nur ein Zuweisungsoperator. Die Memberobjekte selber werden vor &quot;betreten&quot; des Rumpfes bereits angelegt (und zwar in der Reihenfolge, in der sie deklariert worden sind). Für eingebaute Datentypen ist das kein wirklicher Unterschied, bei Objekten hingegen schon. Die zwei Möglichkeiten sind dann in deinem Beispiel folgende:</p>
<p>a) Initialisierungsliste für Klasse2:<br />
das Objekt vom Typ Klasse1 wird an dem zugehörigen Platz mittels des Konstruktors Klasse(Klasse2*) konstruiert. Ende.</p>
<p>b) Operator= im Rumpf:<br />
- das Objekt wird, da keine Initliste, am zugehörigen Platz mittels default-Ctor konstruiert.<br />
- Im Rumpf wird mit Klasse1(this) ein zweites (temporäres) Objekt vom Typ Klasse1 mittels des Konstruktors Klasse1(Klasse2*) erstellt<br />
- Klasse1::operator= wird für objekt aufgerufen, als Argument erhält er das temporäre Objekt<br />
- das temporäre Objekt wird wieder zerstört</p>
<p>Na, welche Version ist kürzer? <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>Und nein, im Konstruktor-Rumpf ist das = kein copy-Ctor, da dort bereits alle Member konstruiert worden sind. Konstruktoren werden pro Objekt immer exakt einmal aufgerufen, und das geschieht für alle Member vor dem Konstruktor-Rumpf.<br />
Die einzige Art, wo ein = einen Copy-Ctor darstellt, ist bei der Definition einer lokalen Variablen:</p>
<pre><code class="language-cpp">class A {
public:
  A(int i);      //Ctor
  A(const A&amp; a); //copy-Ctor
};

int main() {
  A a1(5); //normaler Ctor
  A a2(a1); //Copy-Ctor
  A a3 = a1;  //Copy-Ctor durch =-Zeichen!
  A a4 = 17;  //ACHTUNG! auch Copy-Ctor
              //der Compiler macht daraus 
//A a4 = A(17); also 2 Ctor-aufrufe (ein temporäres Objekt)
//der Copy-Ctor _kann_ hier allerdings wegoptimiert werden (muss aber nicht)
}
</code></pre>
<p>Was die Geschwindigkeitsvorteile von blanken Arrays gegen STL-Container angeht, so können da durchaus gewisse Vorteile sein. Es ist aber fraglich, ob du genau an der Stelle durch die Verwendung von dynamischen Arrays so viel wett machst. Selbst wenn das Programm oft läuft, musst du immernoch die aufsummierten Mikrosekunden gegenrechnen gegen den Aufwand, den op=, den Dtor, den Copy-Ctor und andere Methoden entsprechend sicher zu tippen, und gegen den Aufwand, die Fehler, die sich bei sowas eigentlich immer irgendwann einschleichen, zu finden und zu beheben. Nicht zu vergessen den Aufwand bei der späteren Wartung, wenn man sich durch das Pointer- und Array-gefrickel wieder durchwursteln muss <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414399</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414399</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Mon, 03 Dec 2007 18:47:47 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 18:50:41 GMT]]></title><description><![CDATA[<p>Hast du bei deiner Klasse denn die Regel der großen Drei beachtet, d.h. auch den Zuweisungsoperator richtig implementiert?<br />
Denn dies ist eine Zuweisung:</p>
<pre><code class="language-cpp">objekt = Klasse1(this);
</code></pre>
<p>und keine Initialisierung.<br />
Und nach der Zuweisung wird sofort der Destruktor des temp. Objekts &quot;Klasse1(this)&quot; aufgerufen, der höchstwahrscheinlich den Speicher für den Zeiger &quot;nummern&quot; löscht (und auch richtigerweise löschen sollte).</p>
<p>Und weil dies eben zu diesen Problemen führt, verwendet man (möglichst) keine Klassen mit dynamischen Speicher, sondern die dafür vorgesehenen Klassen der Standard C++ Library (z.B. std::vector, std::deque etc).</p>
<blockquote>
<p>Ich habe außerdem absichtlich auf jede Art von STL-Datenverwaltung verzichtet, weil soweit ich weiß blanke Arrays immer noch am schnellsten sind, und mir das in meinem Fall sehr wichtig ist.</p>
</blockquote>
<p>und dies ist blanker Unsinn...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414403</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414403</guid><dc:creator><![CDATA[Th]]></dc:creator><pubDate>Mon, 03 Dec 2007 18:50:41 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Mon, 03 Dec 2007 19:38:30 GMT]]></title><description><![CDATA[<blockquote>
<p>Zitat:<br />
Ich habe außerdem absichtlich auf jede Art von STL-Datenverwaltung verzichtet, weil soweit ich weiß blanke Arrays immer noch am schnellsten sind, und mir das in meinem Fall sehr wichtig ist.</p>
<p>und dies ist blanker Unsinn...</p>
</blockquote>
<p>Genau, blanker Unsinn.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414431</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414431</guid><dc:creator><![CDATA[simon.gysi]]></dc:creator><pubDate>Mon, 03 Dec 2007 19:38:30 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Tue, 04 Dec 2007 14:44:31 GMT]]></title><description><![CDATA[<p>zu Th:</p>
<p>Also da war mein Missverständnis. Was ich gelesen hatte, bezog sich nur auf lokale Variablen. Aber so aus Interesse: Was macht denn dann eigentlich der Standard-Zuweisungs-Operator für eine neue Klasse, wenn man ihn nicht selbst schreibt? Ich könnte mir vorstellen, dass er einfach alle Variablen eins zu eins kopiert. Was passiert aber dann mit komplexeren Datentypen der zuzuweisenden Klasse?</p>
<p>Wäre es denn vorteilhaft hier die Variable objekt als Zeiger anzulegen? Dann müsste man natürlich kein komplettes Objekt kopieren und würde einfach beim Anlegen den new-Operator mit rein bringen. Allerdings müsste man beim Zugriff auf das Objekt jedes Mal einen Zeiger dereferenzieren. Wie macht ihr das denn bei solchen Fällen eher? (Oder lässt sich die Frage gar nicht so allgemein beantworten...)</p>
<p>Gut, vielleicht das mit den Arrays ist blanker Unsinn. Aber gibt es denn auch Zahlen, wie viel blanker Unsinn das ist? Also sind diese STL-Klassen tatäschlich genau so schnell wie reine Arrays. Es mag ja ein Vorurteil sein, aber immerhin wird ja bei diesen Klassen wohl noch verschiedenes Management ausgeführt, oder nicht? Also würde ich ja intuitiv sagen, dass da doch ein Unterschied sein müsste. Ich lasse mich aber auch gerne vom Gegenteil überzeugen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414821</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414821</guid><dc:creator><![CDATA[David Schneider]]></dc:creator><pubDate>Tue, 04 Dec 2007 14:44:31 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Tue, 04 Dec 2007 15:13:40 GMT]]></title><description><![CDATA[<p>David Schneider schrieb:</p>
<blockquote>
<p>Was macht denn dann eigentlich der Standard-Zuweisungs-Operator für eine neue Klasse, wenn man ihn nicht selbst schreibt? Ich könnte mir vorstellen, dass er einfach alle Variablen eins zu eins kopiert. Was passiert aber dann mit komplexeren Datentypen der zuzuweisenden Klasse?</p>
</blockquote>
<p>Er weist alle Elemente einzeln zu. Wenn diese komplexe Datentypen mit eigenen Zuweisungsoperatoren sind, werden diese benutzt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414853</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414853</guid><dc:creator><![CDATA[Bashar]]></dc:creator><pubDate>Tue, 04 Dec 2007 15:13:40 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Tue, 04 Dec 2007 15:18:06 GMT]]></title><description><![CDATA[<blockquote>
<p>Was macht denn dann eigentlich der Standard-Zuweisungs-Operator für eine neue Klasse, wenn man ihn nicht selbst schreibt? Ich könnte mir vorstellen, dass er einfach alle Variablen eins zu eins kopiert. Was passiert aber dann mit komplexeren Datentypen der zuzuweisenden Klasse?</p>
</blockquote>
<p>Genau, er kopiert alle Member 1:1. Für komplexe Datentypen (nicht PODs) wird deren Zuweisungsoperator aufgerufen.</p>
<blockquote>
<p>Wäre es denn vorteilhaft hier die Variable objekt als Zeiger anzulegen?</p>
</blockquote>
<p>Nein.</p>
<blockquote>
<p>Also sind diese STL-Klassen tatäschlich genau so schnell wie reine Arrays.</p>
</blockquote>
<p>Zugriffe auf vector mit operator[] sollten genau so schnell sein wie bei einem Array. Hier gibt es keinen Overhead und keine Indexprüfung (normalerweise). Der Operator sollte inline implementierbar sein.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1414857</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1414857</guid><dc:creator><![CDATA[Braunstein]]></dc:creator><pubDate>Tue, 04 Dec 2007 15:18:06 GMT</pubDate></item><item><title><![CDATA[Reply to Objekt-Initialisierung on Tue, 04 Dec 2007 20:07:06 GMT]]></title><description><![CDATA[<p>Braunstein schrieb:</p>
<blockquote>
<blockquote>
<p>Was macht denn dann eigentlich der Standard-Zuweisungs-Operator für eine neue Klasse, wenn man ihn nicht selbst schreibt? Ich könnte mir vorstellen, dass er einfach alle Variablen eins zu eins kopiert. Was passiert aber dann mit komplexeren Datentypen der zuzuweisenden Klasse?</p>
</blockquote>
<p>Genau, er kopiert alle Member 1:1. Für komplexe Datentypen (nicht PODs) wird deren Zuweisungsoperator aufgerufen.</p>
</blockquote>
<p>Der Zuweisungsoperator der nicht-statischen Member wird grundsätzlich aufgerufen, unabhängig vom Typ - im Falle von Klassen (POD oder nicht-POD) ist das ein Funktionsaufruf (der des jeweiligen für diese Klasse überladenen - explizit oder implizit deklarierten - Zuweisungsoperators), sonst der eines normalen Operators (Im Falle von Arrays als Membern wird der Operator für jedes einzelne Element aufgerufen). Andernfalls könnte man ja z.B. auch POD-Klassen mit konstanten Membern zuweisen.<br />
Ein interessanter Aspekt des implizit deklarierten Zuweisungsoperators ist, dass er nicht exceptionsicher ist, falls irgendeines außer dem ersten Member bei der Zuweisung eine Exception werfen könnte. Das kann mal zu einer Abweichung der Regel der 3 führen, indem in entsprechenden Fällen nur der Zuweisungsoperator extra implementiert werden muss.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1415007</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1415007</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 04 Dec 2007 20:07:06 GMT</pubDate></item></channel></rss>