Laden...

Warum darf man Referenztypen in Strukturen deklarieren?

Erstellt von barzefutz vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.538 Views
B
barzefutz Themenstarter:in
95 Beiträge seit 2007
vor 14 Jahren
Warum darf man Referenztypen in Strukturen deklarieren?

Hallo,

mal eine Verständnisfrage. Strukturen sind, soweit ich weiss, Werttypen und werden zur besseren Performance auf dem Stack abgelegt. Aber wieso darf eine Struktur dann z.B. einen String enthalten, der ja ein Referenztyp ist? Und Referenztypen werden doch nicht auf dem Stack abgelegt? Wenn eine Struktur ein Werttyp ist, wäre es doch nur logisch, wenn diese auch nur Werttypen enthalten darf.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo barzefutz,

... und werden zur besseren Performance auf dem Stack abgelegt.

das Gerücht hält sich hartnäckig. Die technische Umsetzung (also der genaue Speicherort) braucht einen normalerweise überhaupt nicht zu interessieren. Und die Performance spielt bei der Entscheidung Werttyp oder Referenztyp normalerweise überhaupt keine Rolle und wäre im Gegenteil sogar meistens ein schlechter Ratgeber. Die Entscheidung Werttyp oder Referenztyp sollte auf konzeptionellen Überlegungen basieren, nämlich ob etwas ein reiner Wert oder ein Objekt (mit Identität) ist.

Aber wieso darf eine Struktur dann z.B. einen String enthalten, der ja ein Referenztyp ist?

Wie so denn nicht?

Wenn eine Struktur ein Werttyp ist, wäre es doch nur logisch, wenn diese auch nur Werttypen enthalten darf.

Finde ich nicht. Warum sollte das logisch sein?

herbivore

B
barzefutz Themenstarter:in
95 Beiträge seit 2007
vor 14 Jahren

Hallo,

danke für deine Antwort. Ich habe in einem Buch gelesen, Strukturen sind effizienter als Klassen, weil sie auf dem Stack abgelegt werden. Ist das also falsch?

Was meinst du mit dem Unterschied zwischen "reiner Wert" und "Objekt mit Identität"? Könntest du vielleicht ein kleines Beispiel geben, ich kann mir darunter nichts vorstellen.

Aber nochmal zu der Eingangsfrage. Wenn ich eine Struktur definiere, die einen Integer und einen String enthält, wird dann später der Integer auf dem Stack und der String im Heap abgelegt? Oder wird beides auf dem Stack abgelegt?

J
237 Beiträge seit 2008
vor 14 Jahren

Soweit ich weiß, wird der String wie gewöhnlich auf dem Heap abgelegt. Was spricht dagegen? Was in der Struktur (also auf dem Stack) gespeichert wird, das ist die Referenz (welche ja im Grunde ein Integer mit 32 bzw. 64 Bit ist). Aber wenn ich eine Methode mit einer Variable eines Refrenztyps habe, dann liegt die Referenz auch auf dem Stack im Bereich der Methode.
Ich bin mir aber auch nicht hundertprozentig sicher.
Vielleicht kann ja herbivore oder jemand anders das besser erklären.

Grüße, JasonDelife.

Beim Programmieren löst man die Probleme, die man nicht hätte, programmierte man nicht.

B
barzefutz Themenstarter:in
95 Beiträge seit 2007
vor 14 Jahren

Aber ich habe es so verstanden, dass Werttypen immer auf dem Stack abgelegt werden, und Referenztypen immer im Heap. Eine Struktur ist per Definition ein Werttyp, also wird sie auf dem Stack abgelegt. Und alle Mitglieder der Struktur werden folglich auch auf dem Stack abgelegt (auch Referenztypen).

Nehmen wir mal an, Referenztypen in Strukturen werden NICHT auf dem Stack abgelegt. Das beisst sich mit der Aussage, dass Strukturen effizienter sind, weil sie auf dem Stack abgelegt werden. Das wäre dann ja falsch. Eine Struktur, die nur aus Strings besteht, würde dann doch komplett im Heap abgelegt werden?!

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo barzefutz,

Ich habe in einem Buch gelesen, Strukturen sind effizienter als Klassen, weil sie auf dem Stack abgelegt werden. Ist das also falsch?

das mit den Stack ist richtig, das mit der Effizienz ist Quatsch. Vergiss dass mit der Effizienz. Du wirst von sehr seltenen Ausnahmen abgesehen nie nennenswerten einen Performanceunterschied feststellen.

Was meinst du mit dem Unterschied zwischen "reiner Wert" und "Objekt mit Identität"?

Integers, DateTime, Size u.ä. sind Beispiele für reine Werte. Es kommt nur auf den Wert an. Eigentlich sind Strings auch reine Werte. String sind aber (ausnahmsweise) aus technischen Gründen als Klasse implementiert. Siehe [FAQ] Besonderheiten der String-Klasse (immutabler Referenztyp mit Wertsemantik).

Person, Form, TreeNode sind Objekte mit Identität. Selbst wenn zwei Objekte (z.B. zwei Forms) haargenau den gleichen Zustand haben, sind sie trotzdem noch zwei verschiedene, unterscheidbare Objekte.

Darauf kommt es an, ob man class oder struct wählt. Auf nichts anderes.

Aber ich habe es so verstanden, dass Werttypen immer auf dem Stack abgelegt werden, und Referenztypen immer im Heap.

Vom Grundsatz ist das richtig. Ausnahmen bestätigen die Regel.

Wichtig ist nur, dass in einer Variable eines Werttyps direkt der Wert steht (Zuweisungen überschreiben den Wert), wogegen in einer Variable eines Referenztyps nur eine Referenz auf das Objekt enthalten ist (Zuweisungen ändern nur die Referenz).

Wenn ich eine Struktur definiere, die einen Integer und einen String enthält, wird dann später der Integer auf dem Stack und der String im Heap abgelegt? Oder wird beides auf dem Stack abgelegt?

Vergiss das mal mit den Stack und dem Heap. Kümmere dich nicht darum, wo was abgelegt wird. Das sind technische Details. Da kümmert sich der Compiler drum.

herbivore

B
barzefutz Themenstarter:in
95 Beiträge seit 2007
vor 14 Jahren

Danke für deine ausführliche Antwort. Ich finde das sehr interessant. Aber so 100% habe ich es noch nicht verstanden (das mit struct vs. Klasse). Bei Person, Form usw. leuchtet mir die Unterscheidung ein. Aber was wäre denn beispielsweise sowas wie DirectoryInfo? Klasse oder Struktur?#
Und noch eine kurze Frage. Nehmen wir mal an, ich habe ein Objekt was die Kriterien einer Struktur erfüllt, aber dieses Objekt wird sehr groß sein. Soll ich es dann trotzdem noch als Struktur deklarieren?

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo barzefutz,

Aber was wäre denn beispielsweise sowas wie DirectoryInfo?

Was DirectoryInfo tatsächlich ist, kannst du ja in der Doku nachschauen. 😃

Aber DirectoryInfo ist wirklich ein interessanter Fall. Weil in dem Moment, wo zwei DirectortyInfos den gleichen Zustand haben, beschreiben sie eigentlich dasselbe Realwelt-Objekt (Verzeichnis). Diese Situation dürfte somit sinnvollerweise gar nicht erst eintreten.

Daher wäre es eigentlich günstiger, wenn es in DirectoryInfo statt eines Konstruktors eine statische Methode DirectoryInfo.GetDirectoryInfo (String path) geben würde, die für ein- und dasselbe Verzeichnis immer dasselbe Objekt liefern würde.

Natürlich gibt es immer Grenzfälle, aber ich denke, dass DirectoryInfo eine Klasse ist, ist schon korrekt. Wenn die Klasse so implementiert wäre, wie im vorigen Absatz beschrieben, wäre es perfekt.

Nehmen wir mal an, ich habe ein Objekt was die Kriterien einer Struktur erfüllt, aber dieses Objekt wird sehr groß sein. Soll ich es dann trotzdem noch als Struktur deklarieren?

Mal abgesehen davon, dass ich den Fall für eher unwahrscheinlich halte, sollte man zunächst eine Struktur definieren. Erst wenn dadurch tatsächlich untragbare Performance-Probleme auftauchen, sollte man - notgedrungen - auf eine Klasse ausweichen.

herbivore

B
barzefutz Themenstarter:in
95 Beiträge seit 2007
vor 14 Jahren

Ah, jetzt habe ich es verstanden. Vielen Dank! Wieder so einiges dazugelernt... 🙂