7

Instead of using a geneirc TList<integer> I have decided to use

TSolutions = array of integer;

And then:

function TEuclidMod.gcdExtended(p, q: integer): TSolutions;
var tmpArr: TSolutions;
begin

 SetLength(tmpArr, 3);

 if (q = 0) then
  begin
   tmpArr[0] := p;
   tmpArr[1] := 1;
   tmpArr[2] := 0;
  end
 else
  begin
   vals := gcdExtended(q, modulo(p,q));
   tmpArr[0] := vals[0];
   tmpArr[1] := vals[2];
   tmpArr[2] := vals[1] - vals[2]*floor(p/q);
  end;

 Result := tmpArr;

end;

The variable vals: TSolutions; is declared private in the class and inside the constructor I am setting its length.


I have read on the docwiki that dynamic arrays are ref counted so I don't have to worry about their lifetime. To be sure I have written:

constructor TEuclidMod.Create;
begin

 SetLength(vals, 3);

end;

destructor TEuclidMod.Destroy;
begin

 vals := nil;
 inherited;

end;

So far this should be fine; vals belongs to the class and I free it on the destruction of the class. What about tmpArr?

My function works correctly. The tmpArr is local, then I call SetLength and I give him a lenght: this is creating on the heap the array if I'm not wrong. But then when I return with Result := tmpArr doesn't it get deleted (tmpArr) since the function goes out of scope? I don't want to return a dangling pointer or something else! I need to be sure that it's not freed.

I guess I'm safe because it is a function and it returns a TSolution so the ref count should be always 1 at least. Is it exact? Basically: even if it's local, is it correctly returned?

But from what I've found on SO, in this case

procedure test;
var a: TSolution;
begin

 SetLength(a, 7);
 //do something

end;

The a is always freed when the procedure goes out of scope!

6
  • 4
    You can ditch tmpArr. Don't declare it and work with Result directly. Also pointless setting vals to nil in destructor. The le destructor does so anyway, no point doing it twice. Commented Aug 30, 2017 at 11:12
  • 4
    It also makes more sense to use TArray<Integer> because is has more flexible type compatibility. And SetLength(vals, 3); is totally wasted since you overwrite vals later. You have quite a deficit of understanding that you aren't aware of. Commented Aug 30, 2017 at 11:15
  • 2
    And having said all of this, you shouldn't be using a dynamic array at all. It should be either a record with three fields, or perhaps a non dynamic array of length 3. I'd say a record was the right choice. Then you can name the fields. Commented Aug 30, 2017 at 11:19
  • 1
    @DavidHeffernan ok thank you for the suggestions! That function is just an overload because I wanted to try the dynamic array way (in fact I've asked to solve a doubt). The one I prefer is procedure getSolutions(aList: TList<integer>); Commented Aug 30, 2017 at 11:27
  • @EmmaRossignoli TList<integer> feel like a heavy container for this application, especially if you don't need any of the functions or benefits added by using a TList. Like David said, a record would probably be a better container - much lighter, stack allocated as a local variable, copied on assignment (which fits your use pattern here) and you get the benefit of named fields which makes your code more readable. Commented Aug 30, 2017 at 11:31

1 Answer 1

7

Dynamic arrays are reference counted. Don't worry about their memory management - just use them; that's what reference counting is for. You don't have to nil the class fields in the destructor. The compiler will remove their reference counts when the object is destroyed.

But then when I return with Result := tmpArr doesn't it get deleted (tmpArr) since the function goes out of scope?

Well, no, because you've returned the array by assigning it to Result and, presumably, the caller is also assigning the result to a new variable in turn. The reference count naturally will remain at least one unless the caller does not also assign the function result to a new variable.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you!! :) So as I suspected the ref count is always >= 1 so it doesn't die?
@EmmaRossignoli If you have a reference to the array in a variable then, yes, it must still have a reference count greater than zero.
For completeness, dynamic arrays are reference counted, but don't follow the CopyOnWrite (COW) pattern, as string type does. If you modify one item of your array, every dandling copied instance will be modified, whereas for string values, a new string instance will be allocated and copied when you modify a char within it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.