Recently, I saw a netizen asking on the Internet: How to determine whether an object pointer is available? In other words, how to determine whether an object pointer points to a real usable object instance? Actually this shouldn't be a problem. Because for the programmer, he should be able to control his program not to access an invalid pointer, because the creation and destruction of all object instances are under his control. And even if there is no direct way to determine whether the object pointer is available, it can also be done through other indirect ways (such as using some identifiers, etc.) (for example, when we destroy an object instance, we set the pointer of the object pointer to is nil). But if we put aside the two points mentioned above and just study whether there is a way to determine whether an object pointer is available in Delphi, what will happen?
In Object Pascal, a class can have two types of methods, one is called object method (Object Method) and the other is class method (Class Method). The so-called object method means that the definition of the method is for an object (or instance), so calling the method needs to be based on an object (or instance). For example, the destructor Destroy of a class is an object method (in fact, we often Most of the methods used are object methods). The class method refers to the definition of the method based on a class of objects, so calling the method does not need to be based on a specific object instance, such as the constructor Create of the class. This has some inspiration for us. Determining whether an object pointer is available seems to be accomplished through the following steps. First, we can determine whether the object pointer is nil. If so, then we are done and it is definitely unavailable; if not, then try to execute an object method of the object to see if there are exceptions such as invalid memory access. This is used to determine whether the object is available. Use the following code to verify our idea:
var
Obj: TObject;
begin
Obj := TObject.Create; //1. Create an object
Obj.Free; //2. Release the object just created, and the memory is recycled at this time
If Obj = nil then //3. Determine whether the pointer is empty (this step is often unsuccessful because the object
//is released, Delphi will not automatically empty the object pointer)
ShowMessage('Object pointer is not available.')
else
begin
Try
If Obj.ClassType = TObject then //4. Call an object method of TObject
ShowMessage('The object type is TObject');
Except
ShowMessage('Object pointer is not available.')
End;
end;
end;
Executing the above code, we find that Obj.ClassType is still available even if Obj.Free has been executed. This shows that not all object methods must depend on an object instance to be accessible. The reason is that this object method does not need to access the memory requested by an object instance. In this sense, the TObject.ClassType method does not look like a real object method, but rather resembles a class method.
Executing the above code, we can also find that when an object executes the Free method, it only releases all the memory it applied for when it was created, but it does not affect the value of the object pointer itself. The object pointer still points to the original memory address. At the same time, due to the particularity of the implementation of some object methods (such as ClassType), even if the object has been released, the result of the object method call is still correct.
To sum up, we can draw a conclusion, that is, whether an object pointer can be judged as available depends on whether the class to which the object pointer belongs provides a way to access the object instance memory - this way can be Methods can also be properties. So, what is the situation now specifically in each category?
TObject, this class is the ancestor class of all classes, there is no way to make a judgment.
TPersistent, derived from TObject, does not need to apply for additional memory when creating an object instance, so there is no way to judge.
TComponent, derived from TPersistent, adds many properties that require additional memory to be applied for when creating an object instance, so in theory, it is judged. The code is as follows:
function ComponentExists(AComponent: TComponent): Boolean;
begin
try
AComponent.Hasparent; //Note: This sentence can also be "AComponent.Tag;"
//Or "AComponent.Name"
result := True;
except
result := False;
end;
end;
By calling ComponentExists, we can know whether an object pointer of type TComponent is available, regardless of whether the object pointer has been released or set to nil.
For other classes, such as TControl, TWinControl, or TButton, etc., as long as they are derived from TComponent, the judgment method of TComponent still applies.
There are other user-defined classes. If they are directly derived from classes that cannot be judged (such as TObject and TPersistent), but there are no attributes that require memory application during instantiation, then there is no way to judge; otherwise, it is possible. According to an example:
Suppose we have a TPerson class defined as follows:
TPerson = Class(TObject)
PRivate
FSex: TSex; // TSex is the gender of the enumeration type;
FFirstName: String;
FLastName: String;
//…
Public
property Sex: TSex read FSex write FSex;
property FirstName: String read FFirstName write FFirstName;
property LastName: String read FLastName write FLastName;
//…
end;
Then, for the pointer Person of type TPerson, you can use the following code to determine whether the pointer is available:
Try
Person.Sex;
//Or Person.FirstName;
//Or Person.LastName;
result := True; //The pointer is available
Except
result := False;//The pointer is not available
end;
What we discussed above is only a technical possibility. The point I want to emphasize is that even if there is a good way to do it, it is not encouraged to do it frequently. Because a program with strict logic should be able to prevent access to an invalid pointer.
More articles