![]() |
Delphi-Version: 7
Variable.Create;
Meint ihr, es würde was bringen, wenn man Emba dazu überredet, die mögen doch endlich mal eine (abschaltbare) Compilerwarnung anzeigen?
Bei
Delphi-Quellcode:
statt
Variable.Create;
Delphi-Quellcode:
Variable := TTyp.Create;
Guuuut, denen, die da am Meisten drauf reinfallen, wird es eh nie helfen, denn - es gibt ja sowieso kein Update für alte Delphi-Versionen (D7, D5 usw.) - und die Anfänger gucken eh selten in das CompilerLog |
AW: Variable.Create;
Wobei das 1. ja nicht falsch ist. Es macht halt in den meisten Fällen halt nicht was der Programmierer damit beabsichtigt.
|
AW: Variable.Create;
Ist das nicht eigentlich immer falsch? Mir fällt spontan kein Anwendungsfall ein, da es doch immer in einer AV enden müsste. Bei TTyp.Create ohne Zuweisung an eine Variable sieht das Fall anders aus.
[edit] Nee, meine Aussage stimmt nicht ganz, wenn die Instanz bereits existiert, würde der Konstruktor noch einmal durchlaufen. Aber wozu braucht man das? [/edit] |
AW: Variable.Create;
Ja, darum auch nur als Warnung/Hinweis und eventuell "abschaltbar".
"Meistens" wäre es ja falsch. Wenn man die Variable vorher entsprechend initialisiert, wäre dieser Aufruf möglich. Man kann damit z.B. erzwingen, daß die "neue" Instanz an einer bestimmten Adresse liegt. (man könnte das Objekt sogar in eine MMF oder in einen Record verfrachten) |
AW: Variable.Create;
Da gibt's ein paar Spezialitäten zu beachten:
|
AW: Variable.Create;
Dort wo Referenzzählung oder ggf. sogar ein Owner ins Spiel kommt, sind auch Dinge wie
Delphi-Quellcode:
denkbar. Und dann stelle man sich vor, SomeMethod() hätte auch noch einen Rückgabewert. Solche Konstrukte habe ich in C# nicht allzu selten benutzt, wenn ich von einer Klasse nur diese eine Funktion eben schnell brauchte. Mit Interfaces sicherlich ähnlich vorstellbar.
TMyClass.Create(someArgument).SomeMethod(someMoreArguments);
|
AW: Variable.Create;
Wenn SomeMethod ein Constructor ist, dann hast du dort die selben Probleme wie bei
Delphi-Quellcode:
.
Variable.Create
Es kommt ja letztendlich, nach dem Compiler, auch wieder auf Folgendes raus. (nur daß hier das Temp initialisiert sien sollte)
Delphi-Quellcode:
Temp := TMyClass.Create(someArgument);
Temp.SomeMethod(someMoreArguments); |
AW: Variable.Create;
Der Konstruktor sollte einfach nach außen hin statisch bzw. in Delphi-Ausdrücken sowas wie eine Klassenmethode sein.
Das Aufrufen auf eine Instanzvariable ergibt dann einfach den Compilerfehler "Instanzmethode 'Create' nicht gefunden, meinten Sie vielleicht den Konstruktor der Klasse ..." Innerhalb des Konstruktors muss man dann natürlich auf die Felder zugreifen können. Ist aber natürlich ein "Breaking Change", und alte Versionen (deren Nutzer es vielleicht eher brauchen) bekommen sowas nicht mit... Ach ja und bei sowas:
Delphi-Quellcode:
MUSS doch ein Compilerfehler kommen wie "Verwendung der nicht zugewiesenen lokalen Variablen 'Reg'" !?
var
Reg : TRegistry; begin Reg.Create; // Compilerfehler bitte hier! try Reg.RootKey:=HKEY_CLASSES_ROOT; Reg.OpenKey('.htm', true); Edit1.Text:=reg.ReadString(''); finally reg.Free; end; end; Aber vermutlich bin ich auch nur von C# verwöhnt :stupid: |
AW: Variable.Create;
Ups, mir fiel erst jetzt auf, dass du den Konstruktor im ersten Beispiel auf die Variable angewendet hast. Das war mir schon so abwegig, dass mein Hirn das vermutlich automatisch anders verstehen wollte :stupid: (Ich hab das so gesehen, dass du dort nur die Zuweisung der Instanz an eine entsprechende Variable weg gelassen hast.)
Da stimme ich dann voll zu. Wenn sich die Konstruktoren von ggf. anderen Factory-Methoden der Klasse unterscheiden lassen (was imho in allen Sprachen so sein dürfte), dann gehört dort definitiv eine "nicht initialisiert" Meldung hin. |
AW: Variable.Create;
Auszug aus der
![]() Zitat:
Benutzen könnte man das um die Instanz erneut zu initialisieren ... habe ich aber noch nie gemacht, und werde ich auch nicht machen PS Ich werde morgen mal versuchen bei einer Komponenten so den Owner zu wechseln, wenn das dann in irgendeiner Art nicht funktioniert, dann schreibe ich einen QC-Eintrag ;) |
AW: Variable.Create;
Unabhängig davon wäre dennoch zumindest eine Warnung angebracht, wenn der Konstruktor einer nicht initialisiertern Variablen aufgerufen wird, wie Himi es eingangs glaube ich meinte. Es mag zwar einer statischen Methode ähneln, aber eine neu initialisierte ungültige Referenz bleibt eine ungültige Referenz.
|
AW: Variable.Create;
Zitat:
|
AW: Variable.Create;
Zitat:
Ich hoffe, von euch ist keiner auf die bescheuerte Idee gekommen, in Konstruktoren ungeprüft irgendwelche Unterobjekte zu erzeugen. Weil das würde dann ja zu Speicherlecks führen sobald man .Create aufruft :mrgreen: Also immer schön:
Delphi-Quellcode:
Oder irre ich mich da?
constructor TMyClass.Create();
begin inherited Create; //hierdurch wird der ursprüngliche Konstruktor aufgerufen if not Assigned(values) values = TStringList.Create(); if not Assigned(nodes) nodes = TObjectList.Create(); end; |
AW: Variable.Create;
Zitat:
|
AW: Variable.Create;
Zitat:
Zitat:
W1036 Variable 'Reg' might not have been initialized |
AW: Variable.Create;
Aber nur weil das Ding lokal deklariert worden ist? Zumindest kommt bei mir kein Hinweis bei Attributen oder globalen Variablen. :?
|
AW: Variable.Create;
Die sind ja auch initialisiert, da knallt es dann eben erst zur Laufzeit.
|
AW: Variable.Create;
Schade, das man das in Object Pascal das 'Create' als Methode vorgesehen und nicht einfach das 'New' erweitert hat. Dabei könnte man jegliche Instantiierungslogik (grauselig!) aus dem Konstruktor und in eine normale Methode verbannen.
Delphi-Quellcode:
Dann wäre auch gleich das Problem des Aufrufs virtueller Methoden im Konstruktor vom Tisch. Aber Objectpascal ist ja auch schon bald 30 Jahre alt und bei C# ist das Problem auch noch aktuell.
Var
a : TSomeClass; c : TClass; b : TSomeClassWithParametrizedConstructor; Begin new(a); assert (a is TSomeClass); new(a, TSomeDerivedClass); assert (a is TSomeClass); assert (a is TSomeDerivedClass); c := TSomeClass; new (a,c); assert (a is TSomeClass); new(b).MyCreateMethod(x,y,z); assert (b is TSomeClassWithParametrizedConstructor); |
AW: Variable.Create;
Zitat:
@Furtbichler: Bitte, werde kein Designer von Programmiersprachen. :stupid: Soweit ich sehen kann, würdest du mehrfache Konstruktoraufrufe weiterhin zulassen? Und die fehlende Variablenzuweisung macht den Code unintuitiv. |
AW: Variable.Create;
Mir gefällt die Syntax mit dem new().
Man weiß einfach, "das Objekt wird hier neu erzeugt" und muss das nicht umständlich über eine Zuweisung und den TClass.Create erledigen (vergisst man in der Eile ja auch nach Jahren nochmal ab und zu). |
AW: Variable.Create;
Warnung ok, ich denke jeder hat schonmal ausversehen die Zuweisung vergessen. Fehler aber definitiv nicht!
Konstrukte wie:
Delphi-Quellcode:
würden dann wohl auch nicht mehr funktionieren.
with TBitmap.Create do
try LoadFromFile(''); finally Free; end; |
AW: Variable.Create;
Gibt imho wichtigeres, als die Sprache idiotensicher zu machen... :roll:
|
AW: Variable.Create;
Zitat:
Delphi-Quellcode:
und nicht
new(a)
Delphi-Quellcode:
;-)
a:=new()
Und bezüglich der Vermeidung eines mehrfachen Konstruktoraufrufes könnte man ja im 'new' prüfen, die Referenz 'a' nil ist und ggf (Compilerswitch) eine Exception werfen ('Possible overwrite of an instantiated object'). Wäre auch nicht doof. Zitat:
|
AW: Variable.Create;
Zitat:
Der Compiler macht intern doch sowas draus:
Delphi-Quellcode:
AutomatischGenerierteLokaleVariable1 := TBitmap.Create;
try AutomatischGenerierteLokaleVariable1.LoadFromFile(''); finally AutomatischGenerierteLokaleVariable1.Free; end; [edit] Upss, du meinst den String? Joar, das wird schwieriger. Es gibt doch jetzt diese Attribute. Darüber könnte man auch Anweisungen für den Compiler generieren, aber das wäre nur "halb" sinnvoll, da der dann nur Konstanten und keine Variablen auswerten könnte. Wenn, dann wäre es besser, wenn man, so wie bei der Index- oder Bereichsprüfung eine Codegenerierung aktivieren könnte, welche beim Programmablauf eine Parameterprüfung entsprechend der Attribute durchführen würde. Allerdings wäre es wohl besser, wenn solche Sachen endlich mal standardmäßig aktiv sind, im Debug-Profil, und man sie geziehlt deaktivieren muß, wenn man Diese nicht will. |
AW: Variable.Create;
Zitat:
Delphi-Quellcode:
und
New
Delphi-Quellcode:
funktioniert nunmal so ähnlich... wenn auch nur für
Dispose
Delphi-Quellcode:
:
object
Delphi-Quellcode:
program tobjectcstr;
type TTest = object constructor Create(a, b: Integer); constructor Create(s: String); destructor Destroy; end; PTest = ^TTest; constructor TTest.Create(a, b: Integer); begin Writeln('Called constructor with ', a, ' & ', b); end; constructor TTest.Create(s: String); begin Writeln('Called constructor with ', s); end; destructor TTest.Destroy; begin Writeln('Called destructor'); end; var t: PTest; begin t := New(PTest, Create(42, 12)); Dispose(t, Destroy); New(t, Create('Hello World')); Dispose(t, Destroy); end.
Code:
(Ich habe jedoch nicht getestet, ob Delphi das auch ohne Probleme schluckt...)
$ fpc tobjectcstr.pas
Free Pascal Compiler version 2.6.2 [2013/02/16] for i386 Copyright (c) 1993-2012 by Florian Klaempfl and others Target OS: Linux for i386 Compiling tobjectcstr.pas Linking tobjectcstr /usr/bin/ld: warning: testoutput/link.res contains output sections; did you forget -T? 33 lines compiled, 0.2 sec $ ./tobjectcstr Called constructor with 42 & 12 Called destructor Called constructor with Hello World Called destructor Gruß, Sven |
AW: Variable.Create;
Zitat:
Und Pascal (bzw Delphi) ist schon lang keine Lehrsprache mehr. |
AW: Variable.Create;
Zitat:
|
AW: Variable.Create;
Gerade durch Zufall entdeckt:
![]() Zitat:
|
AW: Variable.Create;
Zitat:
|
AW: Variable.Create;
Stimmt, hab ich dann auch gemerkt, verwirrend sieht es aber allemal aus.
|
AW: Variable.Create;
Blöd, wenn man eine Initialisierungsmethode nach einem Konstruktor benennt.
|
AW: Variable.Create;
Delphi-Quellcode:
tja.
TRegEx = record // <<<<<<<<<<<<<<<<<
private ... public constructor Create(const Pattern: string); overload; constructor Create(const Pattern: string; Options: TRegExOptions); overload; Und ja, in Delphi könnte man diesen Contructor auch Init nennen. Wobei hier auch TRegEx.Create funktionieren würde. |
AW: Variable.Create;
Ist das denn bei Records überhaupt ein Konstruktor? Ich meine nein, denn da wird nichts konstruiert.
|
AW: Variable.Create;
Zitat:
Vergleiche Record einfach mit Klassen in C++: Es ist egal, ob das Objekt auf dem Heap oder auf dem Stack liegt, es wird mit einem Konstruktor erstellt und mit einem Destruktor zerstört. |
AW: Variable.Create;
Bei neuen Delphiversionen ist ein Record mehr als ein Record. Es handlet sich um die Ablösung des alten OBJECTes
![]() |
AW: Variable.Create;
Zitat:
Delphi-Quellcode:
Geht dann nicht mehr? Das geht doch seit Pascal 0.1a so... würde mich doch sehr stark wundern, wenn 99.999% der legacy Delphi-Software dann nicht mehr funktioniert.
Var
myRecord : TMyRecord; Begin myRecord.FooBar := 23; So wie ich den Link im DocWiki verstehe, ist ein Record weiterhin ein Record und lebt auch ohne Aufruf des Konstruktors sofort. Das bedeutet: Wenn ich den Konstruktor nicht aufrufen muss, dann kann er ja nicht viel konstruieren, denn ob ich den nun aufrufe oder nicht, ändert am Record nichts, außer eben, das irgend etwas initialisiert wird. Ergo ist das ein Initialisator (was ein dämliches Wort ist), in jedem Fall eine simple Methode. Was auch sein könnte: Wenn ich einen Recordkonstruktor definiere, dann *muss* ich den auch verwenden, das wird aber aus dem kleinen Absatz nicht ersichtlich... |
AW: Variable.Create;
Zitat:
Zitat:
[ Also gibt es einen implizieten Aufruf eines Default-Constructors, welcher nichts macht (und vermutlich auch keinen Code produziert).![]() Ich gebe zu, dass das Ganze etwas angeflanscht wirkt :mrgreen: |
AW: Variable.Create;
Zitat:
|
AW: Variable.Create;
Zitat:
Wirkt trotzdem ziemlich krude. |
AW: Variable.Create;
Zitat:
Muss ich also den eigenen Konstruktor aufrufen oder nicht? Wenn ja => Konstruktor hat seinen Namen verdient. Wenn nein => Ist das kein Konstruktor.
Delphi-Quellcode:
Könnte das mal jemand testen? Danke....
Type
TMyRecord = Record bar : Integer; Constructor Foo(Bar : Integer); End; Constructor TMyRecord.Foo(Bar : Integer); Begin Self.bar := Bar; End; Var x,y : TMyRecord; Begin y.Foo(27); // Muss man das so machen? x.bar := 27; // Oder geht es auch so? Knallt es hier? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz