[Delphi/C++] Omgaan met "dangling" pointers

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Anoniem: 44809

Topicstarter
Hoe kan ik controleren of een variabele van een object nogwel naar een object verwijst (een andere methode dan object = nil, want dit werkt niet...)??? Ik heb nl. een app waarbij ik een object creer, maar waarbij een andere
functie dit object destroyed.

Zie onderstaande code ter verduidelijking...
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
type TWin = class (TObject);

var Win: TWin;
    P: Pointer;

procedure DestroyApp (P: Pointer);
var Ctrl: TWin;
begin
 Ctrl := TWin (P);
 Ctrl.Free;
end;

procedure CreateWin;
begin
 Win := TWin.Create;
end;

begin
 CreatWin;

 P := Pointer (Win);
 
 //Hier komt code van het programma te staan...
 
 DestroyApp (P);
 
 //Wat moet ik nu doen om te controleren of dat Win wel
 //nog naar een TWin object wijst??? Win = nil werkt
 //niet...
 
 Win.Free //Resulteert in foutmelding "Read of Adress..."
end.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22-06 18:55
code:
1
2
if Assigned(objectje) then 
...

Dacht ik.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22-06 18:55
Hmm:
Note:Assigned can't detect a dangling pointer--that is, one that isn't nil but no longer points to valid data. For example, in the code example for Assigned, Assigned won't detect the fact that P isn't valid.
uit de help van Delphi.

Het is te zien of uw object naar nil wijst of naar een ongeldige waarde...

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Anoniem: 44809

Topicstarter
Op dinsdag 07 mei 2002 13:44 schreef whoami het volgende:
Het is te zien of uw object naar nil wijst of naar een ongeldige waarde...
Assigned werkt helaas niet (heb 't geprobeerd), ik heb namelijk te maken met een "dangling" pointer, en "Assigned can't detect a dangling pointer"... :?

Acties:
  • 0 Henk 'm!

  • Arzie
  • Registratie: Juni 1999
  • Laatst online: 07:41
Zet anders in DestroyApp dat hij P naar nil laat wijzen aan het eind.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22-06 18:55
Op dinsdag 07 mei 2002 13:52 schreef Arzie het volgende:
Zet anders in DestroyApp dat hij P naar nil laat wijzen aan het eind.
Idd, dan werkt het wel.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Anoniem: 2881

In een try..except loopje controleren? Als er dan een fout optreedt (omdat niet meer assigned is), dan kun je iig afvangen...

Quick and dirty, maar goed, werkt toch!

Misschien zou je in de destroy expliciet op nil kunnen zetten? (of FreeAndNil gebruiken). Of bij de OnDestroy de parameter als "var" declareren en P ook op nil zetten?

Acties:
  • 0 Henk 'm!

Anoniem: 44809

Topicstarter
Om mijn probleem ietsjes meer te verduidelijken heb ik hieronder een gedeeltje van de code van het desbetreffende progje neergezet...

Het progje heb ik met Win32 API opgebouwd, volgens het "Controller-Model".
Hierbij sla ik bij het maken v/e window (met CreateWindowEx) de pointer van het object in het progje (de Win variabele) op in de GWL_USERDATA van het window.
Als de WindowProc een WM_DESTROY message krijgt destroyed deze het window, en destroyed het object waar de pointer in GWL_USERDATA naar wijst.
Daardoor is de vaiabele Win een dangling pointer geworden, deze wijst niet meet naar "valid" data.
Nu wil ik op het laatst van het programma "de boel netjes afsluiten", door het Win object ook nog eens af te breken, indien dit niet meer bestaat.

Zie de onderstaande code voor de globale structuur van het progje:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
type
 TController = class (TObject)
  Hwnd: THandle;
  HwndParent: THandle;
  constructor Create(X:integer; Y:integer; Width:integer; Height:integer; Brush: HBrush; Caption:string; Style:integer; StyleEx:integer; HwndParent:THandle);
  destructor Destroy; override;
  procedure Close;
  function OnClose: Boolean; virtual;
  function OnCreate: Boolean; virtual;
  function OnDestroy: Boolean; virtual;
 end;

type
  TWin = class (TController)
  end;

var
  Win: TWin;

function WinProc (Hwnd:THandle; message:integer; wParam:WPARAM; lParam:LPARAM) : LRESULT; stdcall;
var Ctrl: TController;
    P: Pointer;
begin
 Ctrl := TController ( GetWindowLong (Hwnd, GWL_USERDATA) );
 case message of
  WM_NCCREATE:  begin
             with PCreateStruct (lParam)^ do Ctrl := TController(lpCreateParams);
             SetWindowLong (Hwnd, GWL_USERDATA, integer(Ctrl));
             Result := DefWindowProc(Hwnd, message, wParam, lParam);
            end;
  WM_CLOSE:     begin
             if Ctrl.OnClose then Result := 0 else Result := DefWindowProc(Hwnd, message, wParam, lParam);
            end;
  WM_CREATE:    begin
             Ctrl.Hwnd := Hwnd;
             if Ctrl.OnCreate then Result := 0 else Result := DefWindowProc(Hwnd, message, wParam, lParam);
            end;
  WM_DESTROY:   begin
             if Ctrl.OnDestroy then Result := 0 else Result := DefWindowProc(Hwnd, message, wParam, lParam);
             Ctrl.Free;
            end;
  else Result := DefWindowProc(Hwnd, message, wParam, lParam);
 end;
end;

constructor TController.Create(X:integer; Y:integer; Width:integer; Height:integer; Brush: HBrush; Caption:string;  Style:integer; StyleEx:integer; HwndParent:THandle);
var WndClass: TWndClassEx;
    s: string;
begin
 inherited Create;
 Self.HwndParent := HwndParent; 
 s := ClassName;
 if GetClassInfoEx(hInstance, PChar(s), WndClass) = False then
  begin
   WndClass.cbSize := SizeOf (TWndClassEx);
   WndClass.style := CS_DBLCLKS or CS_HREDRAW or CS_OWNDC or CS_VREDRAW;
   WndClass.lpfnWndProc := @WinProc;
   WndClass.cbClsExtra := 0;
   WndClass.cbWndExtra := 0;
   WndClass.hInstance := hInstance;
   WndClass.hIcon := LoadIcon (hInstance, 'MAINICON');
   WndClass.hCursor := LoadCursor (0, IDC_ARROW);
   WndClass.hbrBackground := Brush;
   WndClass.lpszMenuName := nil;
   WndClass.lpszClassName := PChar(s);
   WndClass.hIconSm := LoadIcon (hInstance, 'SMALLICON');
   if RegisterClassEx (WndClass) = 0 then DisplayError ('Register Window Class Failed.');
  end;
 Hwnd := CreateWindowEx (StyleEx, PChar(s), PChar(Caption), Style, X, Y, Width, Height, HwndParent, 0, hInstance, Self);
 if Hwnd = 0 then DisplayError ('Create Window Failed.');
end;

destructor TController.Destroy;
begin
 inherited Destroy;
end;

procedure TController.Close;
begin
 SendMessage (Hwnd, WM_CLOSE, 0, 0);
end;

function TController.OnClose: Boolean;
begin
 Result := False;
end;

function TController.OnCreate: Boolean;
begin
 Result := False;
end;

function TController.OnDestroy: Boolean;
begin
 Result := False;
end;

procedure InitializeAppl;
begin
 Win := TWin.Create (10, 10, 200, 100, GetStockObject (WHITE_BRUSH), 'Win', WS_SYSMENU, WS_EX_TOOLWINDOW, 0);
end;

procedure MessageLoop;
var Msg: TMsg;
begin
 while GetMessage (Msg, 0, 0, 0) do
  begin
   DispatchMessage (Msg);
  end;
end;

procedure FinalizeAppl;
begin
 Win.Free; //Hier weet ik dus niet precies hoe ik kan
 // controleren ofdat Win wel nog naar een geldig object
 // verwijst... Win.Free resulteert in een foutmelding...
end;

begin
 InitializeAppl;
 MessageLoop;
 FinalizeAppl;
end.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22-06 18:55
In de case van WM_DESTROY, een statement toevoegen dat Win op nil zet.

Dan zou Assigned moeten werken, zoals reeds vermeld werd.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12:13

Creepy

Tactical Espionage Splatterer

of i.p.v. ctrl.free een FreeAndNil(ctrl)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

Anoniem: 44809

Topicstarter
Op dinsdag 07 mei 2002 18:13 schreef Creepy het volgende:
of i.p.v. ctrl.free een FreeAndNil(ctrl)
Heb ik net geprobeerd, maar dan krijg ik nog altijd een foutmelding als ik het window afsluit... (als Win.Free in FinalizeAppl wordt aangeroepen) :?

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12:13

Creepy

Tactical Espionage Splatterer

Wat voor foutmelding geeft ie precies dan??

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

Anoniem: 44809

Topicstarter
Op dinsdag 07 mei 2002 21:37 schreef Creepy het volgende:
Wat voor foutmelding geeft ie precies dan??
Ik krijg dan de foutmelding:

"Exception EAccessViolation in module Project1.exe at 0000000.
Acess violation at address 00000000. Read of address 00000000."

Wel heb ik tussentijds nog een "halve" oplossing voor mijn probleem gevonden...
code:
1
2
3
4
5
6
7
8
9
10
11
type TWin = class (TController)
 function OnDestroy: Boolean; override;
end;

var Win: TWin;

function TWin.Destroy: Boolean;
begin
 Win.Free;
 Result := False;
end;

Acties:
  • 0 Henk 'm!

Anoniem: 15854

FreeAndNil werkt hier natuurlijk niet:
code:
1
2
3
4
5
6
7
8
9
10
11
var
  P, Q: TObject;
begin
  P := TObject.Create;
  Q := P;
  ListBox1.Items.Add(Format('P = %d', [Integer(P)]));
  ListBox1.Items.Add(Format('Q = %d', [Integer(Q)]));
  FreeAndNil(P);
  ListBox1.Items.Add(Format('P'' = %d', [Integer(P)]));
  ListBox1.Items.Add(Format('Q'' = %d', [Integer(Q)]));
end;

P is op het einde nul, maar Q bevat nog het adres naar het object, dat niet meer bestaat.

Oplossingen zouden kunnen zijn:
  • Structureel geheugen beheer toepassen, door bv een byte meer te alloceren, bij het creeeren van een object en daar de toestand van het object in te zetten. MemCheck doet zoiets bv.
  • Referenties naar het object, met het object meegeven. Dus een pointer naar een pointer naar het object, zodat deze pointer naar het object op nil gezet kan worden.
  • Observer pattern toepassen, zodat via een callback gemeld kan worden of het object gedestroyed is, etc.
Pagina: 1