Look at:
PlayedWord1 := TWord.Create(...); PlayedWord2 := PlayedWord1
You still only have ONE TWord.
You do have 2 references to it. But only one instance. (you only called .Create once).
PlayedWord1 is internally a pointer.
PlayedWord2 := PlayedWord1 only copies that pointer. (pointing to the same memory, allocated once by calling .Create)
PlayedWord1.Destroy; will free the memory. But both variables point to the same memory, so both variables become invalid.
If that is not your problem, then you probably need to share more of your code.
The above problem would normally crash at the line "wrd:=wordrec.Word;" (or later).
But if you enabled certain checks, it may crash at the line you indicated.
--
The other question is, what is in "c" as in "for i := 0 to c - 1"?
That's because you are adding to wordsplayed
wordsplayed.Add(PlayedWord);
And retrieving from playedwords
wordrec := Tword(PlayedWords[ i ]);
If these are actual codes you are using.
Do you by any chance at any time later do?
PlayedWord.Destroy; // or .Free or FreeAndNir()
So if I do:If you did not make any copy of the reference (that is, if you did not add it to any list, or assigned it to a global var), then you have a memory leak. There is no garbage collection for classes.
word := Tword.create('Cat','Word',false); playedwords.add(word);
And I don't free "word" .. if word is a local variable what happens when it goes out of scope?
Then the next question is how do I later assign a variable to Tword(playedwords[0])? Or is my way working but likely I had done word.free? I'll have to go back and look.
playedwords is the argument to the procedure
If you did not make any copy of the reference (that is, if you did not add it to any list, or assigned it to a global var), then you have a memory leak. There is no garbage collection for classes.
You might want to rethink your naming...
"word_rec" sounds like it is of typewhich differs from a class.
type TSomething = record ... end;
PlayedWord vs PlayedWords => you gonna misread it at sometime....
use
PlayedWord and PlayedWordsList
Even all the integers c,s,r,d,p....
Give them longer names.
i,c are fine.
Use syncro edit https://wiki.lazarus.freepascal.org/New_IDE_features_since#Syncron-Edit , once you written the code. (That is what I do, start with short names, then rename them)
Select the entire procedure and rename them.
(Imho 3 to 4 single letter vars are ok, but over that and give them longer names)
Quoteplayedwords is the argument to the procedure
Actually I didn't think that would be the reason. Just wanted to check such basic points.
I recommend you to use generics if you are to use TObjectList, etc. for classes, so that you do not have to typecast the item every time.
WordList = specialize TFPGObjectList<TWord>;
At the same time you may think of setting TFPGObjectList.FreeObjects to True, becuase removing an item from the list will free the object.
if you specialize and Object list then that is the type that objectlist will automatically expect and contain?
I guess I'm confused on how to properly keep track of this stuff. Should I be defining a global variable as a Tword and then just re-use it when I need to reference one of the TWords in my list? I can see it helps to understand the memory implications.
Even if your variable "wordrec" goes out of scope and no other variable carries the address of the object, it will still be in the memory. So although its still there on the heap, but you don't know where, so you wouldn't have any chance to access it. Thats whats called a 'memory leak'.
You said:QuoteEven if your variable "wordrec" goes out of scope and no other variable carries the address of the object, it will still be in the memory. So although its still there on the heap, but you don't know where, so you wouldn't have any chance to access it. Thats whats called a 'memory leak'.
So if I define wordrec in global scope (interface section) and then I assign it when creating a TWord (wordrec := Tword.create) and then add wordrec to a list (playedwordslist.add(wordrec)) for the sake of example lets call that index 0 .. and then later do the same thing (wordrec := Tword.create) and then add to playedwordslist (index 1) can I go back and forth between index 0 and 1 using (wordrec := Tword(playedwordslist[0]) and [1]) without having a memory leak as long as wordrec is global in scope?
You mean something like
.... Var MyWord1, MyWord2:TWord; .... MyWord1:=TWord.Create('cats','word',false); //DoSomething with MyWord1 MyWord2:=MyWord1; //DoSomething with MyWord2 MyWord1:=TWord.Create('dogs','word',false); //DoSomething with MyWord1 //Never once calling Free on any of the Variables
The pointer in the variable, and the instance in memory are 2 separate things.
- The pointer is controlled by := or list.add.
- The instance memory is controlled by Create/Destroy
Using :=/list.add does not change the instance memory.
And using Create/Destroy does not affect any pointers.
"What happens if you "loose" your credit-card? Correct! You cannot access your money anymore"
Yes, however losing my credit card (or keeping with the analogy, cutting up my credit card (destroy) ) doesn't orphan my bank account. I can still get another credit card to access the same account. :o
Could be even shorter, by setting the string list to reject duplicates and not using an intermediate var:
function TData.GetCategories: TStringList; var i : integer; begin Result := TStringlist.Create; Result.Duplicates := dupIgnore; for i:=0 to Words.Count - 1 do Result.Add(Tword(words[i]).Category); end;
If the account is closed, you have to find each card and cut it. If you don't, and you accidentally try to use it to pay, you go to jail.
Not sure yet whether I want my list sorted... hmm....Although technically possible, if the list is not sorted detecting duplicates can soon be impossibly slow.
Rich
Well to go for the banking analogy.
What will happen with my money (created object) then?
QuoteWhat will happen with my money (created object) then?
This is a swiss bank account, and the bank will charge you for keeping the account open, and if you do not pay, Interpol will inspect you for keeping possible dark money. :D
If the memory is not freed, it is regarded as taken and not available to other applications.
Well to go for the banking analogy.
What puzzles me in this analogy is this: Why do I have to close my account in the end (Free, Destroy) if I still have money on the account?
What will happen with my money (created object) then? :)
And now everybody knows, how the IRS sniffs out the "black-money-accounts":
They are memory-leaks :D :D :D :D :D