Delphi-PRAXiS
Seite 109 von 192   « Erste     95999107108109 110111119159     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Klatsch und Tratsch (https://www.delphipraxis.net/34-klatsch-und-tratsch/)
-   -   Was nervt euch so, während der Programmierung oder so allgemein (https://www.delphipraxis.net/152540-nervt-euch-so-waehrend-der-programmierung-oder-so-allgemein.html)

BUG 12. Jul 2012 23:55

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Beim Entwickeln mit Zeigern fand ich Assertions immer recht hilfreich um zu sehen wo invalide Zeiger in die Datenstruktur kommen, auch wenn sie da noch nicht benutzt werden.
Wenn man dann noch darauf achtet, das die Zeiger immer einen definierten Zustand haben und man typisierte Zeiger benutzt, kann gar nicht mehr so viel schief gehen (ausgenommen der Frage: wo/wann geben ich den Speicher wieder frei).
Rechnen mit Zeigern sollte man tatsächlich nur betreiben, wenn man gut ausgeschlafen ist. Am besten werden diese Berechnungen dann in Prozeduren/Methoden gekapselt und ordentlich typisiert.

jaenicke 13. Jul 2012 05:26

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Delphi-Laie (Beitrag 1174547)
Generisch hin, (un)typisiert her. Mir geht es einfach nur um eine doppelt verkettete Liste. Allein bei deren Deklaration bekam ich schon zu Turbo-Pascal-Zeiten einen dicken Hals: Wie kann etwas sich selbst vollständig als echte Teilmenge enthalten? Das ist mit mathematischer Logik nicht faßbar, das gibt es n.m.W. nur bei unendlichen Mengen. Inzwischen weiß ich, wie das gemeint ist.

Warum brauchst du denn für eine doppelt verkettete Liste explizite Pointer? :gruebel:

Zitat:

Zitat von Delphi-Laie (Beitrag 1174547)
Wenn man diesen Unrat wenigstens vernünftig debuggen könnte, ist aber leider Fehlanzeige.

Ich habe mal kurz eine doppelt verkettete Liste geschrieben, die kann ich auch sehr gut debuggen (wobei ich die geschrieben und einmal testweise gestartet habe und es lief :wink:):
Delphi-Quellcode:
type
  TDoubleLinkedListEntry<T> = class
  private
    var
      FValue: T;
      FPrevious: TDoubleLinkedListEntry<T>;
      FNext: TDoubleLinkedListEntry<T>;
    procedure SetValue(const Value: T);
    procedure SetNext(const Value: TDoubleLinkedListEntry<T>);
    procedure SetPrevious(const Value: TDoubleLinkedListEntry<T>);
  public
    constructor Create(const AValue: T; const APrevious, ANext: TDoubleLinkedListEntry<T>);
    property Value: T read FValue write SetValue;
    property Previous: TDoubleLinkedListEntry<T> read FPrevious write SetPrevious;
    property Next: TDoubleLinkedListEntry<T> read FNext write SetNext;
  end;

  TDoubleLinkedList<T> = class
  private
    var
      FHead, FTail: TDoubleLinkedListEntry<T>;
    type
      TListEnumerator = class
      private
        var
          FFirst: Boolean;
          FCurrent: TDoubleLinkedListEntry<T>;
      public
        constructor Create(AList: TDoubleLinkedList<T>);
        property Current: TDoubleLinkedListEntry<T> read FCurrent;
        function MoveNext: Boolean;
      end;
  public
    destructor Destroy; override;
    procedure Append(const Value: T);
    procedure Delete(const Value: T);
    procedure Remove(const Value: TDoubleLinkedListEntry<T>);
    function GetEnumerator: TListEnumerator;
    property Head: TDoubleLinkedListEntry<T> read FHead;
    property Tail: TDoubleLinkedListEntry<T> read FTail;
  end;

{ TDoubleLinkedListEntry<T> }

constructor TDoubleLinkedListEntry<T>.Create(const AValue: T; const APrevious, ANext: TDoubleLinkedListEntry<T>);
begin
  FValue := AValue;
  FPrevious := APrevious;
  FNext := ANext;
end;

procedure TDoubleLinkedListEntry<T>.SetNext(const Value: TDoubleLinkedListEntry<T>);
begin
  FNext := Value;
end;

procedure TDoubleLinkedListEntry<T>.SetPrevious(const Value: TDoubleLinkedListEntry<T>);
begin
  FPrevious := Value;
end;

procedure TDoubleLinkedListEntry<T>.SetValue(const Value: T);
begin
  FValue := Value;
end;

{ TDoubleLinkedList<T> }

destructor TDoubleLinkedList<T>.Destroy;
var
  CurrentEntry: TDoubleLinkedListEntry<T>;
begin
  if Assigned(FHead) then
  begin
    CurrentEntry := FHead;
    while Assigned(CurrentEntry.Next) do
    begin
      CurrentEntry := CurrentEntry.Next;
      CurrentEntry.Previous.Free;
    end;
    FTail.Free;
  end;
  inherited;
end;

function TDoubleLinkedList<T>.GetEnumerator: TListEnumerator;
begin
  Result := TListEnumerator.Create(Self);
end;

procedure TDoubleLinkedList<T>.Append(const Value: T);
begin
  if Assigned(FTail) then
  begin
    FTail.Next := TDoubleLinkedListEntry<T>.Create(Value, FTail, nil);
    FTail.Next.Previous := FTail;
    FTail := FTail.Next;
  end
  else
  begin
    FTail := TDoubleLinkedListEntry<T>.Create(Value, FTail, nil);
    FHead := FTail;
  end;
end;

procedure TDoubleLinkedList<T>.Remove(const Value: TDoubleLinkedListEntry<T>);
begin
  if Assigned(Value.Previous) then
    Value.Previous.Next := Value.Next;
  if Assigned(Value.Next) then
    Value.Next.Previous := Value.Previous;
end;

procedure TDoubleLinkedList<T>.Delete(const Value: T);
var
  CurrentEntry: TDoubleLinkedListEntry<T>;
begin
  CurrentEntry := FHead;
  while Assigned(CurrentEntry) do
    if TComparer<T>.Default.Compare(CurrentEntry.Value, Value) = 0 then
    begin
      Remove(CurrentEntry);
      CurrentEntry.Free;
      Break;
    end
    else
      CurrentEntry := CurrentEntry.Next;
end;

{ TDoubleLinkedList<T>.TListEnumerator }

constructor TDoubleLinkedList<T>.TListEnumerator.Create(AList: TDoubleLinkedList<T>);
begin
  FFirst := True;
  FCurrent := AList.Head;
end;

function TDoubleLinkedList<T>.TListEnumerator.MoveNext: Boolean;
begin
  Result := Assigned(FCurrent) and (Assigned(FCurrent.Next) or FFirst);
  if Result and not FFirst then
    FCurrent := FCurrent.Next;
  FFirst := False;
end;
Benutzung:
Delphi-Quellcode:
var
  Test: TDoubleLinkedList<Integer>;
  CurrentEntry: TDoubleLinkedListEntry<Integer>;
begin
  Test := TDoubleLinkedList<Integer>.Create;
  try
    Test.Append(100);
    Test.Append(300);
    Test.Append(200);
    for CurrentEntry in Test do
      ShowMessage(IntToStr(CurrentEntry.Value)); // 100, 300, 200
    Test.Delete(300);
    for CurrentEntry in Test do
      ShowMessage(IntToStr(CurrentEntry.Value)); // 100, 200
  finally
    Test.Free;
  end;
end;
Und debuggen kann ich das auch problemlos:

Anhang 37262

Sicher, explizite Zeiger braucht man an manchen Stellen natürlich. Solange man das ganze durchdacht strukturiert machen die aber auch nicht mehr Probleme als andere Sprachbestandteile.

Ein Beispiel, das ich beruflich vor einer Weile brauchte, war ein generischer Ringpuffer. Da dort auch z.B. Records hineingespeichert werden können sollten, brauchte ich einen Pointer auf die gespeicherten Daten um diese verändern zu können. Dies wird leider nicht komplett unterstützt, aber vom Prinzip her sah das am Ende so aus:
Delphi-Quellcode:
  TCircularBuffer<T> = class
  public
    type
      TBufferPointer = ^T;
  strict private
    var
      FElements: TArray<T>;
  // ...
  public
    type
      TBufferEnumerator = class(TEnumerator<TCircularBuffer<T>.TBufferPointer>)
      // ...
      public
        constructor Create(ABuffer: TCircularBuffer<T>);
        property Current: TCircularBuffer<T>.TBufferPointer read GetCurrent;
        function MoveNext: Boolean;
      end;
    function GetEnumerator: TBufferEnumerator; reintroduce;
    // ...
  end;
Ohne Generics und den Pointer in Kombination wäre das gar nicht möglich das typsicher so umzusetzen. Aber trotzdem ist das ganze immer noch typsicher.

Namenloser 13. Jul 2012 08:45

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Ich wünschte ich hätte Generics :(

Edit: Btw ich verstehe nicht, wieso immer alle auf Pointern rumhacken. Wenn der Code mit Pointern schwer zu debuggen ist, wäre er mit Objekten oder Referenzen (wenn Delphi sowas hätte) genau so schwer zu debuggen. Es liegt an der Struktur des Codes, nicht an den Pointern.

Ich verwende manchmal Pointer, vor allem wenn ich mit irgendwelchen Buffern hantiere, und habe damit eigentlich nie Probleme.

Daniel 13. Jul 2012 09:13

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Ich denke da gerade an Beispiel aus C, bei denen es Pointer auf Pointer gab, die dann *huppsala* wieder auf Pointer zeigten. Das hat schon ein gewisses Potential für einen Knoten im Hirn. Einen einfachen Pointer auf eine Datenstruktur jedoch sehe ich nun auch nicht als "per se" problematisch an - bei vielen API-Funktionen von Windows ist es die einzige Art, diese zu verwenden.

DeddyH 13. Jul 2012 09:16

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
In Delphi ist das intern ja auch nicht anders, bleibt dem Entwickler aber zum größten Teil verborgen (zum Glück).

mkinzler 13. Jul 2012 09:55

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Delphi referenziert/dereferenziert auch automatisch.

Delphi-Laie 13. Jul 2012 16:26

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Na, da habe ich wohl wieder etwas losgetreten. Also das gute vorweg: Ich nahm mich der Sache noch einmal an, und jetzt funktioniert es. Es ist die Langzahlenarithmetik aus dem "Arbeitsbuch für Turbo Pascal 4.0" aus dem ehrenhaften Jahre 1988. Delphi mit seiner beeindruckenden Abwärtskompatibilität hat an "nur-Turbo-Pascal-tauglichen" Quelltexten als solchen natürlich überhaupt nichts auszusetzen. Ein Fehler war m.E. schon im Buch, bei einem anderen bezweifele ich, daß er auch in Turbo-Pascal schon auftrat. Wenn ein Variablenparameter in einer Prozedur einen anderen Wert hat (auch unmittelbar vor ihrem Verlassen) als danach, dann sieht man ganz schon alt aus, weil sich diese Wertänderung beim Debuggen nicht nachverfolgen läßt. Der andere Wert ist aus heiterem Himmel eben plötzlich da. Da ich so etwas vorher noch nie hatte, blieb mir nichts anderes übrig, als "die bösen Zeiger" als Schuldige auszumachen, weil (für mich) kaum nachvollziebar ist, wann nur Zeiger (=Adressen) und wann Speicherinhalte geändert werden. Vielleicht lag in einem dieser Nebeneffekte ja die Ursache.

Zitat:

Zitat von jaenicke (Beitrag 1174555)
Zitat:

Zitat von Delphi-Laie (Beitrag 1174547)
Generisch hin, (un)typisiert her. Mir geht es einfach nur um eine doppelt verkettete Liste. Allein bei deren Deklaration bekam ich schon zu Turbo-Pascal-Zeiten einen dicken Hals: Wie kann etwas sich selbst vollständig als echte Teilmenge enthalten? Das ist mit mathematischer Logik nicht faßbar, das gibt es n.m.W. nur bei unendlichen Mengen. Inzwischen weiß ich, wie das gemeint ist.

Warum brauchst du denn für eine doppelt verkettete Liste explizite Pointer? :gruebel:

Ich weiß nicht, was ein "expliziter" Pointer ist und ob es auch andere (implizite?) gibt. Es ging und geht um doppelt verkettete Listen, bei denen man sich über Zeiger von Element zu Element - vorwärts oder rückwärts dank der doppelten Verkettung - hangeln kann / muß. Das meiste ist in Routinen enthalten und mithin mehr oder weniger versteckt, gekapselt , so daß ich mich nicht darum kümmern mußte (so z.B. mit new und dispose neue Listenwerte anzulegen bzw. alte zu annullieren. Das ganze wird ständig über den ^ -Operator referenziert, adressiert, wie auch immer, das sind nach meiner Kenntnis Zeiger, also ist das gesamte "Rumgemache" (neu"deutsch": Handling) eben "total verzeigert". Und das führt zu allen möglichen Neben-/Seiteneffekten, die ich weiter oben schon bemängelte. Delphi hat sogar mit seiner Stabilität zu kämpfen (hielt sich aber wacker), und nach dem Schließen der IDE wird man auch noch mal mit irgendeiner Fehlermeldung (access violation?) verabschiedet. Sind wirklich eine ekelhafte Angelegenheit, diese Zeiger. Wenn es funktioniert, flutscht es wie am Schnürchen und ist sehr schnell, aber wehe, es steckt irgendwo ein Fehler (eher schon: er versteckt sich) und man steht vor der Aufgabe, diesen aufzuspüren.

jaenicke 13. Jul 2012 16:42

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Ach so, du machst das mit Records. Das macht es unnötig kompliziert. Mit Klassen wie in meinem Beispiel geht es einfacher. Das sind implizite Pointer, weil das einfach eine Variable mit einem Objekt drin ist. Ein expliziter Pointer ist ein Pointer auf einen Record oder so, den man auch als solchen behandeln muss.

Wichtig ist natürlich auch immer, dass man die einzelnen Funktionen möglichst kurz und übersichtlich macht und nicht zu viel in eine. Das lässt sich sonst gerade bei etwas komplexerer Logik (gut ist ne doppelt verkettete Liste nicht wirklich, aber zumindest ein bisschen) schwer sehen, ob das so richtig ist.

Jedenfalls hilft da FastMM beim Debuggen, weil man da Stacktraces bekommt wo das Objekt erzeugt und wo freigegeben wurde, wenn man danach noch einmal darauf zugreift.

Namenloser 17. Jul 2012 15:40

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
So allgemein nervt mich, dass bei etlichen Verpackungen das Mindesthaltbarkeitsdatum völlig woanders steht als „Mindestens haltbar bis:“. Es ist eine Kleinigkeit, aber einfach unnötig. Wenn es eh darauf hinausläuft, dass ich die ganze Verpackung nach dem erstbesten Datum absuchen muss und einfach davon ausgehen muss, dass es sich dabei um das Mindesthaltbarkeitsdatum handelt, könnten sie sich den Text auch gleich sparen.

jaenicke 17. Jul 2012 16:27

AW: Was nervt euch so, während der Programmierung oder so allgemein
 
Zitat:

Zitat von NamenLozer (Beitrag 1174954)
So allgemein nervt mich, dass bei etlichen Verpackungen das Mindesthaltbarkeitsdatum völlig woanders steht als „Mindestens haltbar bis:“. [...] könnten sie sich den Text auch gleich sparen.

Das würden viele sich sicher auch gerne sparen, aber wenn du einmal in die Verordnung über die Kennzeichnung von Lebensmitteln in Paragraph 7 Abschnitt 2 schaust, siehst du warum das nicht geht.
Zitat:

Das Mindesthaltbarkeitsdatum ist unverschlüsselt mit den Worten "mindestens haltbar bis ..." unter Angabe von Tag, Monat und Jahr in dieser Reihenfolge anzugeben. Die Angabe von Tag, Monat und Jahr kann auch an anderer Stelle erfolgen, wenn in Verbindung mit der Angabe nach Satz 1 auf diese Stelle hingewiesen wird.
Ähnlich steht dies in der europäischen Neufassung in Verordnung 1169/2011 unter Anhang X drin:
Zitat:

1. Das Mindesthaltbarkeitsdatum wird wie folgt angegeben:
a) Diesem Datum geht folgende Angabe voran:
— „mindestens haltbar bis …“, wenn der Tag genannt wird;
— „mindestens haltbar bis Ende …“ in den anderen Fällen.
b) In Verbindung mit der Angabe nach Buchstabe a wird angegeben
— entweder das Datum selbst oder
— ein Hinweis darauf, wo das Datum in der Kennzeichnung zu finden ist.
Diese Angaben werden erforderlichenfalls durch eine Beschreibung der Aufbewahrungsbedingungen ergänzt, deren
Einhaltung die angegebene Haltbarkeit gewährleistet.
c) Das Datum besteht aus der unverschlüsselten Angabe von Tag, Monat und gegebenenfalls Jahr in dieser Reihen*
folge.
[...]
Ich halte das aber auch für sinnvoll, dass man den Text nicht ganz entfernen darf, denn wenn nicht einmal da stehen muss wo man das Datum finden, sucht man sich erst recht tot...


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:04 Uhr.
Seite 109 von 192   « Erste     95999107108109 110111119159     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz