Delphi Programming Guide
Delphi Programmer 

Menu  Table of contents

Part I - Foundations
  Chapter 1 – Delphi 7 and Its IDE
  Chapter 2 – The Delphi Programming Language
  Chapter 3 – The Run-Time Library
  Chapter 4 – Core Library classes
  Chapter 5 – Visual Controls
  Chapter 6 – Building the User Interface
  Chapter 7 – Working with Forms
Part II - Delphi Object-Oriented Architectures
  Chapter 8 – The Architecture of Delphi Applications
  Chapter 9 – Writing Delphi Components
  Chapter 10 – Libraries and Packages
  Chapter 11 – Modeling and OOP Programming (with ModelMaker)
  Chapter 12 – From COM to COM+
Part III - Delphi Database-Oriented Architectures
  Chapter 13 – Delphi's Database Architecture
  Chapter 14 – Client/Server with dbExpress
  Chapter 15 – Working with ADO
  Chapter 16 – Multitier DataSnap Applications
  Chapter 17 – Writing Database Components
  Chapter 18 – Reporting with Rave
Part IV - Delphi, the Internet, and a .NET Preview
  Chapter 19 – Internet Programming: Sockets and Indy
  Chapter 20 – Web Programming with WebBroker and WebSnap
  Chapter 21 – Web Programming with IntraWeb
  Chapter 22 – Using XML Technologies
  Chapter 23 – Web Services and SOAP
  Chapter 24 – The Microsoft .NET Architecture from the Delphi Perspective
  Chapter 25 – Delphi for .NET Preview: The Language and the RTL
  Appendix A – Extra Delphi Tools by the Author
  Appendix B – Extra Delphi Tools from Other Sources
  Appendix C – Free Companion Books on Delphi
  List of Figures    
  List of tables    
  List of Listings    
  List of Sidebars  

Previous Section Next Section

Delphi's Object Reference Model

In some OOP languages, declaring a variable of a class type creates an instance of that class. Delphi, instead, is based on an object reference model. The idea is that a variable of a class type, such as the TheDay variable in the preceding ViewDate example, does not hold the value of the object. Rather, it contains a reference, or a pointer, to indicate the memory location where the object has been stored. You can see this structure depicted in Figure 2.4.

Click To expand
Figure 2.4: A representation of the structure of an object in memory, with a variable referring to it

The only problem with this approach is that when you declare a variable, you don't create an object in memory (which is inconsistent with all other variables, confusing new users of Delphi); you only reserve the memory location for a reference to an object. Object instances must be created manually, at least for the objects of the classes you define. Instances of the components you place on a form are built automatically by the Delphi library.

You've seen how to create an instance of an object by applying a constructor to its class. Once you have created an object and you've finished using it, you need to dispose of it (to avoid filling up memory you don't need any more, which causes what is known as a memory leak). This can be accomplished by calling the Free method. As long as you create objects when you need them and free them when you're finished with them, the object reference model works without a glitch. The object reference model has many consequences on assigning object and on managing memory, as you'll see in the next two sections.

Assigning Objects

If a variable holding an object only contains a reference to the object in memory, what happens if you copy the value of that variable? Suppose you write the BtnTodayClick method of the ViewDate example in the following way:

procedure TDateForm.BtnTodayClick(Sender: TObject);
  NewDay: TDate;
  NewDay := TDate.Create;
  TheDay := NewDay;
  LabelDate.Caption := TheDay.GetText;

This code copies the memory address of the NewDay object to the TheDay variable (as shown in Figure 2.5); it doesn't copy the data of one object into the other. In this particular circumstance, this is not a very good approach—you keep allocating memory for a new object every time the button is clicked, but you never release the memory of the object the TheDay variable was previously pointing to.

Click To expand
Figure 2.5: A representation of the operation of assigning an object reference to another object. This is different from copying the actual content of an object to another.

This specific issue can be solved by freeing the old object, as in the following code (which is also simplified, without the use of an explicit variable for the newly created object):

procedure TDateForm.BtnTodayClick(Sender: TObject);
  TheDay := TDate.Create;

The important thing to keep in mind is that, when you assign an object to another object, Delphi copies the reference to the object in memory to the new object reference. You should not consider this a negative: In many cases, being able to define a variable referring to an existing object can be a plus. For example, you can store the object returned by accessing a property and use it in subsequent statements, as this code snippet indicates:

  ADay: TDate;
  ADay := UserInformation.GetBirthDate;
  // use a ADay

The same thing happens if you pass an object as a parameter to a function: You don't create a new object, but you refer to the same one in two different places in the code. For example, by writing this procedure and calling it as follows, you'll modify the Caption property of the Button1 object, not of a copy of its data in memory (which would be totally useless):

procedure CaptionPlus (Button: TButton);
  Button.Caption := Button.Caption + '+';
// call...
CaptionPlus (Button1)

This means that the object is being passed by reference without the use of the var keyword and without any other obvious indication of the pass-by-reference semantic, which also confuses newcomers. What if you really want to change the data inside an existing object, so that it matches the data of another object? You have to copy each field of the object, which is possible only if they are all public, or provide a specific method to copy the internal data. Some classes of the VCL have an Assign method, which performs this copy operation. To be more precise, most of the VCL classes that inherit from TPersistent, but do not inherit from TComponent, have the Assign method. Other TComponent-derived classes have this method but raise an exception when it is called.

In the DateCopy example, I've added an Assign method to the TDate class and called it from the Today button, with the following code:

procedure TDate.Assign (Source: TDate);
  fDate := Source.fDate;
procedure TDateForm.BtnTodayClick(Sender: TObject);
  NewDay: TDate;
  NewDay := TDate.Create;
  LabelDate.Caption := TheDay.GetText;

Objects and Memory

Memory management in Delphi is subject to three rules, at least if you allow the system to work in harmony without Access Violations and without consuming unneeded memory:

  • Every object must be created before it can be used.

  • Every object must be destroyed after it has been used.

  • Every object must be destroyed only once.

Whether you must perform these operations in your code or can let Delphi handle memory management for you depends on the model you choose among the different approaches provided by Delphi.

Delphi supports three types of memory management for dynamic elements:

  • Every time you create an object explicitly in your application code, you should also free it (with the only exception of a handful of system objects and of objects that are used through interface references). If you fail to do so, the memory used by that object won't be released for other objects until the program terminates.

  • When you create a component, you can specify an owner component, passing the owner to the component constructor. The owner component (often a form) becomes responsible for destroying all the objects it owns. In other words, when you free a form, it frees all the components it owns. So, if you create a component and give it an owner, you don't have to remember to destroy it. This is the standard behavior of the components you create at design time by placing them on a form or data module. However, it is mandatory that you choose an owner that you can guarantee will be destroyed; for example, forms are generally owned by the global Application objects, which is destroyed by the library when the program ends.

  • When Delphi's RTL allocates memory for strings and dynamic arrays, it will automatically free the memory when the reference goes out of scope. You don't need to free a string: When it becomes unreachable, its memory is released.

Destroying Objects Only Once

If you call the Free method (or call the Destroy destructor) of an object twice, you get an error. However, if you remember to set the object to nil, you can call Free twice with no problem.


You might wonder why you can safely call Free if the object reference is nil, but you can't call Destroy. The reason is that Free is a known method at a given memory location, whereas the virtual function Destroy is determined at run time by looking at the type of the object—a very dangerous operation if the object no longer exists.

To sum things up, here are a couple of guidelines:

  • Always call Free to destroy objects, instead of calling the Destroy destructor.

  • Use FreeAndNil, or set object references to nil after calling Free, unless the reference is going out of scope immediately afterward.

In general, you can also check whether an object is nil by using the Assigned function. The following two statements are equivalent in most cases:

if Assigned (ADate) then ...
if ADate <> nil then ...

Notice that these statements test only whether the pointer is not nil; they do not check whether it is a valid pointer. If you write the following code, the test will be satisfied, and you'll get an error on the line with the call to the object method:

if ToDestroy <> nil then

It is important to realize that calling Free doesn't set the object to nil.

Previous Section Next Section



Delphi Sources

Copyright © 2004-2024 "Delphi Sources" by BrokenByte Software. Delphi Programming Guide
ร๐๓๏๏เ ยส๎ํ๒เ๊๒ๅ   Facebook   ั๑๛๋๊เ ํเ Twitter