2014-01-16 50 views
6

我在论坛上看了很多关于指针的帖子,Assigned函数,Free函数,FreeAndNil函数等等...我已经知道了自由函数不会删除指向指定对象的指针引用并且FreeAndNil是不是......所有文章I阅读对待这个主题考虑Create方法已经执行,或换句话说,考虑一个已经创建的对象。为什么Assigned对未初始化的变量返回true?

我的问题是:为什么Assigned函数对未初始化的对象变量返回true?

的榜样:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    Qry: TADOQuery;  
begin 
    if Assigned(Qry) then 
    ShowMessage('Assigned') 
    else 
    ShowMessage('Unassigned'); 

    Qry := TADOQuery.Create(nil); 

    if Assigned(Qry) then 
    ShowMessage('Assigned') 
    else 
    ShowMessage('Unassigned'); 
end; 

这个例子显示 '分配' 的两倍!

结论:紧随Qry已被声明并且在其创建方法执行之前,指向Qry的指针不是NIL

如果我把Qry := nil;放在第一行到上面的程序中,一切正常......它显示'Unassigned'和'Assigned'。

为什么?

是否有任何安全的方法来知道一个类变量是否已经执行了它的create方法?

+4

看看这个:http://stackoverflow.com/questions/132725/are-delphi-variables-initialized-with-a-value-by-default – idursun

+1

“类变量已经执行了它的create方法“变量没有任何方法! 'var o:TObject;我:整数; s:弦乐;我:= TStringList.Create.Count; s:= TStringList.UnitName; o:= TStringList.Create;' - 这三个语句中的每一个都有相同的结构:有一些任何表达式,它计算一些任何值;并且存在值(但不是表达式,该点不再存在)的变量被保存到。当表达式被执行时(用这些“方法”)还没有var。当有变化 - 没有更多的表达 –

回答

3

因为当创建一个指针时,它带有任何垃圾值在该内存位置。如果你想写NIL,它需要一些CPU周期,我认为它不是由Delphi自动完成的,因为你可能想要更快的东西。在你的例子中,为什么把NIL分配给一个变量,如果不久之后你会把另一个值放进去呢?

+2

我不知道为什么你被拒绝了(两次)。 –

+0

看起来像一些人在答案中的问题有问题吗? (即使rethorical问题...) – Rodrigo

7

您的变量是局部变量,因此未初始化。它可以包含任何值。

documentation说:

Win32平台的 内容的局部变量是不确定的,直到一个值分配给 他们。

请注意,作为实现细节,某些类型被管理,甚至托管类型的局部变量也被初始化。托管类型的示例包括:字符串,接口,动态数组,匿名类型和变体。

你问:

有没有知道,如果一个类变量已经拥有了创建方法执行任何安全的方式?

如果该变量是局部变量,则答案为否。程序员对你负有责任。在实践中,它很少是一个问题,因为良好的代码具有简短的程序,这使得你很难滑落。即使你这样做,编译器也会一直提醒你。

其他类型的变量,如类字段和全局变量被初始化。

+0

我认为德尔福/ LLVM初始化类指针,因为它们就像那里的接口指针。我想知道是否有很多“错误”报告,例如“我的应用在iPad上工作正常,但变量在iOS模拟器上失败无测试”;-) –

4

Assigned函数(重点煤矿)的文档:

使用分配给确定被P所引用的指针或过程是否是零。 P必须是指针或过程类型的变量引用。 指定的(P)对应于针对指针变量的测试P <> nil,对于程序变量,测试P <>零。

如果P为零,则分配返回false,否则返回true。

注意:Assigned不能检测悬挂指针 - 即,不是零但不再指向有效数据的指针。例如,在分配的代码示例中,分配不会检测到P无效的事实。

Assigned功能得到有效实施为:

function Assigned(const P): Boolean; 
begin 
    Result := Pointer(P) <> nil; 
end; 

因此函数是不是真的检查值是否真的被分配。而是检查分配的副作用。

  • 其结果的功能是保证返回True如果分配
  • 但是,如果值为未初始化,则行为未定义。基本上,由于未初始化的值具有先前操作遗留的垃圾值,因此可能是,或者如果可能不是

要注意的另一件事是Assigned无法确定其值的有效性。例如。即使底层对象不再有效,以下呼叫Assigned也会返回True

var 
    LObject: TObject; 
begin 
    LObject := TObject.Create; 
    LObject.Free; 
    if Assigned(LObject) then ShowMessage('Still assigned!?'); 
end; 

编辑:附录

在回答你问题的第二部分。

是否有任何安全的方法知道一个类变量是否已经执行了它的create方法?

没有安全的方法来确定是否创建了一个对象实例。 (也没有办法可靠地确认它还没有被销毁。)

但是,有一些约定(和良好的做法),你可以按照以帮助你的方式。

首先请注意,如果创建了某些代码的故意功能,则应该只是“不确定”。例如。如果你打算让一个对象“懒惰初始化”。

  • 我想在这里说的是:决不检查Assigned仅仅是因为你担心,有可能是防止它被分配了一个错误。
  • 这不仅是不可能做到可靠,但你过分复杂的代码...其中增加错误的机会。
  • 此外,如果您发现意外未分配的东西,那么您可以对此做些什么?忽略它会简直毫无意义。另外,没有什么好说的:“好吧,然后我会创建对象”。因为这样你就可以在多个地方复制创建逻辑。
  • 基本上你应该尽量让你的程序的每个部分都正确 - 你的程序不要试图在任何地方进行仔细检查。

所以,现在,我们(希望)同意,如果事情是创建如果你刻意选择了为创建是可选的,你只检查。你这样做如下:

  • 在第一次机会,确保变量/场参考被初始化。因此,它被保证被分配一个值,这意味着该对象不被创建。 (是的,命名有点扭曲
  • 您可以将可放大/字段引用设置为对象的新实例,或者通过复制已存在对象的另一个引用来设置它。 (注现有refernce也可能是,但这并不会引起任何问题。
  • 如果你破坏对象(甚至只是想停止使用从基准),设置您的变量/现场参考再次。
  • 注意:Delphi已经初始化一个新类的成员字段。所以这些不需要特别的关注。
相关问题