第一段:不出错是因为你把那个strstr做成了tform1里的一个成员。成员的初始化在对象的初始化里完成。所以,第二段当然会出错。

解决方案 »

  1.   

    to BigBen(江南草):strstr并不是tform1成员吧?
      

  2.   

    hehe,打...手!没看清题目就乱答。研究研究,应该不难嘛。
      

  3.   

    是不是因为tstrings是一个抽象类,里面很多方法都是空的,没有实现。
      

  4.   

    关于free,如果是一个对象,仅仅set nil是不够的,因为在windows系统里它还是有登记项在的。就是简单的指针,把它set nil在程序里也是不好的。并不能总保证你的程序正常退出,那样就会有所谓的内存泄露了。
    关于{}就是编译开关指示字。可以找object pascal参考书仔细看看。{$R *.DFM}的意思是编译所有以dfm(delphi form)文件,从那个文件里读窗口信息。再如{r icons.res}就是指示编译icons.res资源文件。
      

  5.   

    3.'{$R *.DFM}'是什么?这些等等的含义是什么?用'{...}'做注释不会有干扰吧? 
    首先说明这不是注释,{$..}注意$符号,他一般作为告诉编译器需要什么!
    {$R ..}一般作为资源文件声明
    {$APPTYPE ..}告诉编译器是什么类型的工程
    如{$APPTYPE CONSOLE}就是说明当前编译的是一个控制台程序
    {$E ..}告诉编译器可以产生什么扩展名
    {$E DEU}
    {$E CPL}
    还有很多,建议你看看帮助
      

  6.   

     Free automatically calls the destructor if the object reference is not nil.Free is successful even if the object is nil,so if the object was never initialized, Free won't result in an error.这就是你第一个程序不出错的原因
      

  7.   

    1 :它是一个全局变量,自动清为0值,而free在指针为0时不产生错误。如果你看VCL的源码就知道了。free操作先判断该指针是否为NIL。
    2 :它是一个局部变量,在堆上分配,不清0,内容为内存里随机量,free时当然会有错误。
    3 :set nil不能释放内存,但p.Free;后加p := nil;是一个好的习惯。
      绝对不要直接p:=nil;因为这样它指向的内存并没有释放!
    其他就如上面各位所说。
      

  8.   

    还有一点大家没提到,为什么重复Free会出错?因为Free时对象被释放,而指针没变,这样指针就指向了一块无效的内存。
      

  9.   

    哪里有object pascal书藉下载?
      

  10.   

    不知道,就不要瞎掰啦。对象的成员在对象被建立的时候,会自动的清空,也就是类似
    FillChar(X, SizeOf(X), 0)
    这样的动作,所以第一个不会错。第二个,局部变量,Delphi是不负责为你初始化的,所以自然会出错啦。第三个,全局变量,同样是会在程序启动时被清空的。procedure tobject.free;
    begin
      if Self <> nil then
        Self.Desroy; //明白为什么Destroy从TObject开始就是Virtual了吧
    end;如果要确定在释放后设为Nil,则可以调用FreeAndNil
      

  11.   

    0.所有类均是TObject的子类。所有的对象实例变量都可看成一个指向对象的指针。1.关于TObject.Free方法。该方法执行时看Self是否为nil,如果为nil就不执行真正的释放操作了。2.类类型的变量,如果是一个类对象的成员、全局变量(interface中定义的)、模块变量(implementation中定义的)都初始化为nil,如果未对之赋值,则执行Free方法不会出错。3.如果是临时变量,即函数、过程或方法中定义的变量,如果未经赋值,则是一个随机值,这样,执行释放操作就会导致错误,因为非法操作了内存。4.一个有效的对象实例变量Free了以后,该变量并不自动变成nil,而是变成指向无效内存的指针,再次Free也会导致错误;另外,给一个对象实例变量赋nil,也不会释放该对象占有的内存,而只可能变成了内存中的一个孤儿。Delphi中没有自动内存回收机制,除非应用程序退出,这块内存会处在无用而浪费的状态。5.{$R *.DFM}是一个Delphi的伪指令,表示包含了与单元同名的.DFM资源文件。Form将资源存在了.DFM文件中。
    {$R filename}
    {$RESOURCE filename}
    The $R directive specifies the name of a resource file to be included in an application or library. The named file must be a Windows resource file and the default extension for filenames is .RES. To specify a file name that includes a space, surround the file name with single quotation s: {$R 'My file'}.
    The * symbol has a special meaning in $R directives: it stands for the base name (without extension) of the source-code file where the directive occurs. Usually, an application抯 resource (.RES) file has the same name as its project (.DPR) file; in this case, including {$R *.RES} in the project file links the corresponding resource file to the application. Similarly, a form (.DFM) file usually has the same name as its unit (.PAS) file; including {$R *.DFM} in the .PAS file links the corresponding form file to the application.{$R filename.RES filename.RC} (where the two occurrences of 'filename' match) makes the .RC file appear in Delphi's Project Manager. When the user opens the .RC file from the Project Manager, the String Table editor is invoked.
    When a {$R filename} directive is used in a unit, the specified file name is simply recorded in the resulting unit file. No checks are made at that point to ensure that the filename is correct and that it specifies an existing file.
    When an application or library is linked (after compiling the program or library source file), the resource files specified in all used units as well as in the program or library itself are processed, and each resource in each resource file is copied to the executable being produced. During the resource processing phase, Delphi's linker searches for .RES files in the same directory as the module containing the $R directive, and in the directories specified in the Search path input box on the Directories/Conditionals page of the Project|Options dialog box (or in the directories specified in a /R option on the DCC32 command line).6.Delphi的光盘上有Documents目录,里面有Object Pascal的手册。也可以看联机帮助。
      

  12.   


    好像有这样一个规则:
     
      一.在访问一个对象时首先要确定该对象的实例是否存在.
      二.在程序中动态建立的对象,你要负责释放.
      三.在释放一个对象后,最好把该对象的指针附成 nil.(好像这样更为安全)
      四.对于Form在释放时建议(Borland这样建议)使用Release.
      五.在程序中不要直接调用Desroy.*象上面的代码, 我不明白你为什么在使用TStrings时不先创建该对象的实例
    (strs :=   TString.Creat),这样写程序很难想像!*对于全局变量编译器自动初始化,局部变量要程序员知己处理.
      

  13.   

    strstr.free;//strstr 在之前不曾被初始化(没能调用strstr:=tstringlist.create)
    strstr.free;//strstr 再次被free,均会产生错误!the help say:free won't result an error even the object is nil实际上定义TstringList的一个实例就相当于定义了一个指针,你还没有create,就是说还没有分配内存空间,这只是个空指针。第二个指针同理。释放一个空指针是会出问题的。应该判断一下,如:if strstr <> nil then .......
      

  14.   

    to:BaldZhang
       你说的那个destory在哪里实现了呢?
      

  15.   

    < Delphi 5:procedure TObject.Free;
    asm
            TEST    EAX,EAX //if Self = nil then
            JE      @@exit  // goto exit;
            MOV     ECX,[EAX] //
            MOV     DL,1     //
            CALL    dword ptr [ECX].vmtDestroy  //call Self.Destroy;
    @@exit:
    end;
    Delphi 6:procedure TObject.Free;
    begin
      if Self <> nil then
        Destroy;
    end;
      

  16.   

    to:BaldZhang
        真不好意思,我还想问一下,  你说的那个destory在哪里实现了呢? 我的意思是在vcl里,
    好象tobject.destory是个空过程,(见笑了),其实这道问题是我自定义的一个class(tobject)中产生的,我也并没有实现destory.
        还有,TEST    EAX,EAX //if Self = nil then 这句是什么意思,难道test eax,eax 不相等吗?(汇编我只是略懂一二,我的基础还是ms51汇编基础。),说不定这是个有代表性的疑问,
    在这里,先谢了,致以崇高的革命敬礼!!!!!!!!
      

  17.   

    1.上面错误是如何产生的,为什么会产生错误? 
        在(1)中你将 strstr 声明为全局变量,全局变量在 Delphi 中,在程序初始化时被设成“零”状态的,也就是 strstr := nil ,而空指针调用 Free 方法是是不会发生异常的(注意没有);在(2)中你将 strstr 声明为局部变量,局部变量在默认时是不会自动清零的,这是它所指的地址是一个随机数,调用 Free 方法时,Free 方法企图去释放这个随机地址的内存,所以发生了异常;在(3)中结合以上讲述,你在注意一点,Free 方法并不会将指针自动清零,实际上指针还是指向原来的内存地址(只不过内存已经被释放),这时你再调用 Free 方法就是二次释放内存了,当然发生异常。
    2.SET NIL 能够释放内存吗? 和free有什么区别?有没有别的办法?或者二选一?
        一般的指针(包括普通对象),Set nil 是不能释放内存的,Set nil 仅仅是将指针所指的内存地址改变(这样就可能丢失了原来已经分配空间的地址)。Free 就是释放指针所指的内存,它内部调用了 VirtualFree win32 API 真正释放内存。但是其中有一个特殊(可以说是超常规的),就是接口对象 interface 的内存释放就是使用 Set NIL 的方法,其实也不奇怪,是 Delphi 编译器在幕后增加了代码。
    3.'{$R *.DFM}'是什么?这些等等的含义是什么?用'{...}'做注释不会有干扰吧? 
       {$xxx} 是编译指令,具体含义你可以查帮助。所以你的注释就不要用 {$ 开头了。
      

  18.   

    to:qkl(康) ;
    Free 就是释放指针所指的内存,它内部调用了 VirtualFree win32 API 真正释放内存。
    我有了一点感性认识了。请示意地给我讲一讲下面的代码,好吗?
    procedure TObject.Free;
    asm
            TEST    EAX,EAX //if Self = nil then
            JE      @@exit  // goto exit;
            MOV    ECX,[EAX] //
            MOV    DL,1    //
            CALL    dword ptr [ECX].vmtDestroy  //call Self.Destroy;
    @@exit:
    end;
    这里的test,je,mov,call的作用我都还了解,请讲讲过程,行吗?
      

  19.   

    首先要了解 EAX 就存放着 self,也就是对象指针(一般在对象内部的方法中 EAX 就是指 self),要知道 nil 其实就是 0 ,知道对象指针指的内存的含义吗?就是函数入口表和对象数据。
    下面看看代码:
        TEST    EAX,EAX // 检查对象是否已经 =nil
        JE      @@exit  // 如果对象已经 =nil,就退出,不做任何事,所以没有异常
        MOV    ECX,[EAX] // 取出函数入口表
        MOV    DL,1      //设标志,以后用到
        CALL   dword ptr [ECX].vmtDestroy // 也就是调用 Destroy 方法,现在你明白为什么最好不直接调用 Destroy 方法了吧没多神秘吧 :)
      

  20.   

    TEST 和 CMP 是一样比较的吗?
      

  21.   

    Delphi的每个对象都有一个虚拟方法表格(VMT),
    其中开头的一些是固定,像Destroy方法就是其中一个,因为Destroy方法声明的时候是声明成Destructor的,所以编译器会自动在这里
    加上释放内存的代码,真要想看的话,方法如下:Projects --> Porject Option --> Compiler --> Debuggin --> Use Debug DCUs
    打勾,然后一直按F7,就可以了。至于汇编,我也基本上不会,:(
    所以,也要让qkl来解释了。
      

  22.   

    type myclass=class
         strstr:tstrings;
    destructor myclass.free;
    end;
    destructor myclass.free;
    strstr.free;
    inherited free;
    end;请大家指正,老有错误!
      

  23.   

    to dyydyy,看不懂你写的代码    另外,才注意你这题给这么多分,你下次不是提问不了?
      

  24.   

    destructor myclass.free;
    begin //******
      strstr.free;
      inherited free;
    end;
      

  25.   

    destructor myclass.free;  destructor这样命名,不妥吧。
    strstr.free  没有Creat就Free,不妥吧。
      

  26.   


    对不起,上面我没有将源程序具体列举出来,语法应不存在错误。
    ***********************************
    type myclass=class
        strstr:tstrings;
    public
    ...//这里我省略了其它一些过程,及成员声明。
    destructor myclass.free;//只讨论free 过程。
    end;destructor myclass.free;
    begin
    strstr.free;//在constructor中我已将它create了而且也没有将在任何其它的过程中free掉。
    inherited free;
    end;
    调用free会产生错误。
    在运行时会产生错误.
    请高手不啬指正。!!谢谢。
      

  27.   

    我用类似的方法作了,没有错误。
    我想问题可能不是Free,而是在于你用的TStrings,它有很多抽象方法和虚方法,你应该使用TStringList.
      

  28.   

    我用的虽然是tstrings,但我是这样创建的;str:=tstringlist.create;这真是怪了。
      

  29.   

    你把源代码给我,我帮你调一下,[email protected]
      

  30.   

    也寄给我一个看看[email protected]
      

  31.   

    解决办法:
    在每次释放时用下面的语句:
    if assigned(strlst) then 
    begin
      strstr.free;
      strstr:=nil;
    end;解释:当把它释放掉以后,指针还是指在老地方,所有要令它为nil,收回指针。
      

  32.   

    你跟踪过了吗,是 strstr.free 语句出错?
    你的 strstr 单单是存放 string 型的变量吗?
    你的程序是多线程方式吗?
      

  33.   

    对,strstr作为一个temail的成员(作用根据客户命令生成email,如作为rcpts,我想这必须使用tstringlist),而且是free出错。
    既然是邮件服务器,不是多线程,怕是完成不任务!而且是非阻塞式的。
      

  34.   

    你不要将Free定义成析构方法destructor,这样在调用Free时实际上是直接调用了析构方法而不会调用上面讨论的TObject.Free。一般来说,不管是C++还是Delphi,应该将析构函数定义成虚方法(虚函数),这样在派生类对象析构时都会安全地调用每一级析构方法。在Delphi中每个类都是TObject的派生类,而TObject中定义了Destroy作为析构方法。它是一个虚方法。每个派生的类需要自己的析构动作时都应该重载这个方法。如:type myclass=class
        strstr:tstrings;
    public
    ...
    destructor destroy; override;
    end;destructor myclass.destroy;
    begin
      strstr.free;//在constructor中我已将它create了而且也没有将在任何其它的过程中free掉。
      inherited;
    end;var myobj: MyClass;这样当你调用myobj.Free时,它用调用TObject.Free方法。如果myobj不为nil,则它会调用MyClass.destroy; 而MyClass.destroy中又调用了TObject.Destroy。调用顺序如下:myobj.Free;  --> TObject.Free --> MyClass.Destroy --> TObject.Destroy。这就保证了每个析构函数的调用。如你所写的,假如
    var
      myobj: TObject;myobj := MyClass.create;myobj.Free; // 这里将调用TObject.Free,但不会调用MyClass.Free,因为TObject.Free不是虚方法。
      

  35.   

    把tstrings改成Tstringlist;
    在使用前创建,不用的时候free;不要直接使用Tstrings类型的变量,详情见delphi的帮助
      

  36.   

    我用了半年的Delphi了,就是不懂Free的用法,我每次用的时候就是会出现异常的错误,搞得我就是不敢用它来优化程序,有哪位高手可以指点小弟几招呀,谢了