Tablice dynamiczne, rzutowanie i wskaźniki.

0

Witam, poniżej mam pewien przykładowy kod:

type
  TTestClass = class
    Argument: Pointer;
    procedure GetData;
    procedure MainProc;
  end;
  TChars = array of Char;

procedure TTestClass.GetData;
var
  S: string;
  A: TChars;
begin
  S := 'Some data :)'#0;
  SetLength(A, Length(S));
  Move(S[1], A[0], Length(S));
  Self.Argument := A; // <-- X
end;

procedure TTestClass.MainProc;
var
  A: TChars;
begin
  Self.GetData;
  A := Self.Argument; // <-- X
  ShowMessage(PChar(A)); // <-- access violation
  A := nil;
end;

powoduje on access violation w oznaczonej linii.

Jeżeli linie oznaczone literą X zamienimy na takie:

Self.Argument := Pointer(A);

Pointer(A) := Self.Argument;

to niby wszystko działa ale access violation pojawia się po zamknięciu formy.

Dopiero takie linie:

TChars(Self.Argument) := A;

A := TChars(Self.Argument);

działają poprawnie.

Pytanie jest następujące: dlaczego? Zawsze myślałem, że rzutowanie jest tylko po to żeby kompilator miał pewność, że wiem, co robię natomiast dane pozostają na swoim miejscu. Dlaczego w tym przypadku rzutowanie ma znaczenie?

Pytanie dodatkowe. Czy jeśli w funkcji F zadeklaruje zmienną lokalną S typu string i przypisze do niej ciąg znaków, a następnie ustawię globalny wskaźnik P na S, to czy po zakończeniu funkcji F, mimo tego że P nadal wskazuje na S, to string S zostanie zwolniony? Bo rozumiem, że tablica dynamiczna na pewno nie zostanie zwolniona dopóki się tego samemu nie zrobi a jak jest ze stringiem?

0

Rzutowanie typów jest dla kompilatora inforamacją o sposobie interpretacji bitów zmiennej. Czyli napisanie czegoś takiego skończy się błędem:

var
 znak: Char;
 liczba: integer;
begin
 znak := 'z';
 liczba := znak; //tu oczywiście jest błąd

ale już coś takiego jest całkowicie prawidłowe:

var
 //zmienne te same co u góry
begin
 znak := 'z';
 liczba := integer(znak);

Zmienna liczba bedzie posiadać kod znaku 'z'. Te same dane (znak 'z') zostały inaczej zinterpretowane.

0

w moim przykladzie jest przypisanie tablicy dynamicznej do wskaznika a potem znowu wskaznika do tablicy wiec kompilator ma to co mial na poczatku, ten sam adres, to samo miejsce w pamieci a jednak nie dziala...

0

Z tym, że próbujesz zapisać tablicę jako wskaźnik, a powinieneś raczej zapisywać ją pod wskaźnikiem.

Self.Argument:=@A;
//lub
Self.Argument:=AllocMem(SizeOf(A));
Self.Argument^:=A;
//oraz
A:=Self.Argument^;

A co do Twojego drugiego pytania, to sam string zostanie zwolniony jako zmienna w pamięci, ale jego zawartość dalej w tej pamięci będzie pod starym adresem. Jednak tylko do chwili nadpisania jej przez inne dane, bo mimo że masz adres tego miejsca, to nie jest ono zarezerwowane, i w każdej chwili program może je znowu wykorzystać.

0
Loloki napisał(a)
A:=Self.Argument^;

hm... ta linijka sie nie kompiluje:
Incompatible types: 'procedure, untyped pointer or untyped parameter' and 'TChars'

1 użytkowników online, w tym zalogowanych: 0, gości: 1