Objektets livslängd

I objektorienterad programmering (OOP) är objektets livslängd (eller livscykel ) för ett objekt tiden mellan ett objekts skapelse och dess förstörelse. Regler för objektlivslängd varierar avsevärt mellan språk , i vissa fall mellan implementeringar av ett givet språk, och livslängden för ett visst objekt kan variera från en körning av programmet till en annan.

I vissa fall sammanfaller objektets livslängd med variabel livslängd för en variabel med det objektet som värde (både för statiska variabler och automatiska variabler ), men i allmänhet är objektets livslängd inte bunden till livslängden för någon variabel. I många fall – och som standard i många objektorienterade språk, särskilt de som använder garbage collection (GC) – allokeras objekt på heapen och objektets livslängd bestäms inte av livslängden för en given variabel: värdet på en variabel att hålla ett objekt motsvarar faktiskt en referens till objektet, inte själva objektet, och förstörelse av variabeln förstör bara referensen, inte det underliggande objektet.

Översikt

Även om grundidén om objektlivslängd är enkel – ett objekt skapas, används och förstörs sedan – varierar detaljerna avsevärt mellan språk och inom implementeringar av ett givet språk, och är intimt knutet till hur minneshantering implementeras . Vidare görs många fina skillnader mellan stegen och mellan begrepp på språknivå och begrepp på implementeringsnivå. Terminologi är relativt standard, men vilka steg som motsvarar en given term varierar kraftigt mellan språken.

Termer kommer vanligtvis i antonympar, en för ett skapande koncept, en för motsvarande förstörelsekoncept, som initialisera/slutföra eller konstruktor/destruktor. Skapande/förstörelseparet är också känt som initiering/avslutning, bland andra termer. Termerna allokering och avallokering eller frigöring används också, i analogi med minneshantering, även om objektskapande och destruktion kan innebära betydligt mer än bara minnesallokering och -deallokering, och allokering/avallokering är mer korrekt övervägda steg i skapandet respektive förstörelsen.

Determinism

En stor skillnad är om ett objekts livstid är deterministisk eller icke-deterministisk. Detta varierar beroende på språk, och inom språket varierar med minnesallokeringen av ett objekt; objektets livslängd kan skilja sig från variabel livslängd.

Objekt med statisk minnesallokering , särskilt objekt lagrade i statiska variabler , och klassmoduler ( om klasser eller moduler själva är objekt, och statiskt allokerade), har en subtil icke-determinism på många språk: medan deras livslängd verkar sammanfalla med körtiden i programmet är ordningen för skapande och förstörelse – vilket statiskt objekt som skapas först, vilket andra, etc. – i allmänhet icke-deterministisk.

För objekt med automatisk minnesallokering eller dynamisk minnesallokering sker objektskapande i allmänhet deterministiskt, antingen explicit när ett objekt explicit skapas (som via new i C++ eller Java), eller implicit i början av variabel livslängd, särskilt när omfattningen av en automatisk variabel matas in, t.ex. vid deklaration. Objektförstöring varierar dock – i vissa språk, särskilt C++, förstörs automatiska och dynamiska objekt vid deterministiska tidpunkter, såsom räckviddsavslut, explicit förstörelse (via manuell minneshantering) eller referensräkning som når noll; medan på andra språk, såsom C#, Java och Python, förstörs dessa objekt vid icke-deterministiska tidpunkter, beroende på sopsamlaren, och objekt kan återuppstå under förstörelsen, vilket förlänger livslängden.

I sopsamlade språk tilldelas objekt i allmänhet dynamiskt (på högen) även om de initialt är bundna till en automatisk variabel, till skillnad från automatiska variabler med primitiva värden, som vanligtvis allokeras automatiskt (på stacken eller i ett register). Detta gör att objektet kan returneras från en funktion ("escape") utan att förstöras. Men i vissa fall är en kompilatoroptimering möjlig, nämligen att utföra escape-analys och bevisa att escape inte är möjligt, och därmed kan objektet allokeras på stacken; detta är viktigt i Java. I det här fallet kommer objektdestruktion att ske omedelbart – möjligen till och med under variabelns livstid (innan dess räckvidd slutar), om den inte går att nå.

Ett komplext fall är användningen av en objektpool , där objekt kan skapas i förväg eller återanvändas, och därmed skenbar skapelse och förstörelse kanske inte motsvarar faktisk skapande och förstörelse av ett objekt, endast (om)initiering för skapande och slutförande för förstörelse. I det här fallet kan både skapande och förstörelse vara icke-deterministiska.

Steg

Objektskapande kan delas upp i två operationer: minnesallokering och initiering , där initiering båda inkluderar att tilldela värden till objektfält och eventuellt köra godtycklig annan kod. Dessa är begrepp på implementeringsnivå, ungefär analogt med distinktionen mellan deklaration och definition av en variabel, även om dessa senare är distinktioner på språknivå. För ett objekt som är knutet till en variabel kan deklarationen kompileras till minnesallokering (reserverar utrymme för objektet) och definition till initiering (tilldelning av värden), men deklarationer kan också vara för kompilatoranvändning (såsom namnupplösning ) , inte direkt motsvarar den kompilerade koden.

Analogt kan objektdestruktion delas upp i två operationer, i motsatt ordning: slutförande och minnesdeallokering . Dessa har inte analoga koncept på språknivå för variabler: variabel livslängd slutar implicit (för automatiska variabler, vid avveckling av stack; för statiska variabler, vid programavslutning), och vid denna tidpunkt (eller senare, beroende på implementering) avallokeras minne, men ingen slutbehandling görs i allmänhet. Men när ett objekts livslängd är knuten till en variabels livslängd, orsakar slutet av variabelns livslängd slutförandet av objektet; detta är ett standardparadigm i C++.

Tillsammans ger dessa fyra steg på implementeringsnivå:

allokering, initiering, slutförande, deallokering

Dessa steg kan göras automatiskt av språkkörningstiden, tolken eller den virtuella maskinen, eller kan specificeras manuellt av programmeraren i en subrutin , konkret via metoder – frekvensen av detta varierar avsevärt mellan steg och språk. Initiering är mycket vanligt programmeringsspecificerad i klassbaserade språk , medan i strikt prototypbaserade språk initiering görs automatiskt genom kopiering. Slutförande är också mycket vanligt i språk med deterministisk förstörelse, särskilt C++, men mycket mindre vanligt i sopsamlade språk. Tilldelning specificeras mer sällan, och omallokering kan i allmänhet inte specificeras.

Status under skapande och förstörelse

En viktig subtilitet är statusen för ett objekt under skapandet eller förstörelsen, och hantering av fall där fel uppstår eller undantag görs, till exempel om skapandet eller förstörelsen misslyckas. Strängt taget börjar ett objekts livstid när allokeringen slutförs och slutar när deallokeringen startar. Alltså under initiering och slutförande är ett objekt levande, men kanske inte är i ett konsekvent tillstånd – vilket säkerställer att klassinvarianter är en nyckeldel av initiering – och perioden från det att initieringen slutförs till när slutförandet startar är när objektet både är levande och förväntas vara i ett konsekvent tillstånd.

Om skapandet eller förstörelsen misslyckas kan felrapportering (ofta genom att göra ett undantag) kompliceras: objektet eller relaterade objekt kan vara i ett inkonsekvent tillstånd, och i fallet med förstörelse – vilket vanligtvis sker implicit, och därmed i en ospecificerad miljö – det kan vara svårt att hantera fel. Den motsatta frågan – inkommande undantag, inte utgående undantag – är om skapande eller förstörelse ska bete sig annorlunda om de inträffar under undantagshantering, när annat beteende kan önskas.

En annan subtilitet är när skapande och förstörelse sker för statiska variabler , vars livslängd sammanfaller med programmets körtid – sker skapande och förstörelse under vanlig programkörning, eller i speciella faser före och efter vanlig körning – och hur objekt förstörs vid program uppsägning, när programmet kanske inte är i ett vanligt eller konsekvent tillstånd. Detta är särskilt ett problem för språk som samlas in som samlas in, eftersom de kan ha mycket skräp när programmet avslutas.

Klassbaserad programmering

I klassbaserad programmering är objektskapande också känt som instansiering (att skapa en instans av en klass ), och destruktor skapande och förstörelse kan styras via metoder som kallas en konstruktor och eller en initialiserare och slutförare . Skapande och förstörelse är alltså också känt som konstruktion och förstörelse, och när dessa metoder kallas ett objekt sägs det vara konstruerat eller förstört (inte "förstört") – respektive initierat eller slutfört när dessa metoder anropas.

Förhållandet mellan dessa metoder kan vara komplicerat, och ett språk kan ha både konstruktörer och initialiserare (som Python), eller både destruktörer och slutbehandlare (som C++/CLI ), eller så kan termerna "destructor" och "finalizer" syfta på språk- nivåkonstruktion kontra implementering (som i C# kontra CLI).

En nyckelskillnad är att konstruktörer är klassmetoder, eftersom det inte finns något objekt (klassinstans) tillgängligt förrän objektet har skapats, men de andra metoderna (destruktörer, initialiserare och slutbehandlare) är instansmetoder, eftersom ett objekt har skapats. Vidare kan konstruktörer och initialiserare ta argument, medan destruktörer och slutförare i allmänhet inte gör det, som de vanligtvis kallas implicit.

I vanlig användning är en konstruktor en metod som direkt anropas explicit av användarkod för att skapa ett objekt, medan "destructor" är subrutinen som kallas (vanligtvis implicit, men ibland explicit) på objektförstöring i språk med deterministiska objektlivslängder – arketypen är C++ – och "finalizer" är den subrutin som sopsamlaren implicit anropar för att förstöra objekt på språk med icke-deterministisk objektlivslängd – arketypen är Java.

Stegen under slutförandet varierar avsevärt beroende på minneshantering: i manuell minneshantering (som i C++, eller manuell referensräkning) måste referenser explicit förstöras av programmeraren (referenser rensas, referensantal minskade); i automatisk referensräkning sker detta även under slutförandet, men det är automatiserat (som i Python, när det inträffar efter att programmerarspecificerade finalizers har anropats); och för att spåra sophämtning är detta inte nödvändigt. Sålunda vid automatisk referensräkning är programmerarspecificerade slutbearbetare ofta korta eller frånvarande, men betydande arbete kan fortfarande göras, medan slutförandet ofta är onödigt när det gäller att spåra sophämtare.

Resurshantering

På språk där objekt har en deterministisk livslängd, kan objektlivslängden användas för att hantera resurshantering : detta kallas Resource Acquisition Is Initialization (RAII) formspråk: resurser förvärvas under initialisering och frigörs under slutförande. På språk där objekt har en icke-deterministisk livslängd, särskilt på grund av sophämtning, hålls hanteringen av minne i allmänhet åtskild från hanteringen av andra resurser.

Objektskapande

I typiska fall är processen som följer:

  • beräkna storleken på ett objekt – storleken är för det mesta densamma som klassens men kan variera. När objektet i fråga inte härrör från en klass, utan från en prototyp istället, är storleken på ett objekt vanligtvis storleken på den interna datastrukturen (t.ex. en hash) som håller dess platser.
  • allokering – allokera minnesutrymme med storleken på ett objekt plus tillväxten senare, om möjligt att veta i förväg
  • bindningsmetoder – detta lämnas vanligtvis antingen till objektets klass eller löses vid avsändning, men det är ändå möjligt att vissa objektmodeller binder metoder vid skapandet.
  • anropar en initialiseringskod (nämligen constructor ) av superklass
  • anropa en initialiseringskod för klass som skapas

Dessa uppgifter kan slutföras på en gång men lämnas ibland oavslutade och ordningen på uppgifterna kan variera och kan orsaka flera konstiga beteenden. Till exempel, i multi-heritance , vilken initieringskod som ska anropas först är en svår fråga att besvara. Superklasskonstruktörer bör dock anropas före underklasskonstruktörer.

Det är ett komplext problem att skapa varje objekt som ett element i en array. [ ytterligare förklaring behövs ] Vissa språk (t.ex. C++) överlåter detta till programmerare.

Att hantera undantag mitt under skapandet av ett objekt är särskilt problematiskt eftersom implementeringen av att kasta undantag vanligtvis bygger på giltiga objekttillstånd. Det finns till exempel inget sätt att tilldela ett nytt utrymme för ett undantagsobjekt när allokeringen av ett objekt misslyckades innan dess på grund av brist på ledigt utrymme i minnet. På grund av detta bör implementeringar av OO-språk tillhandahålla mekanismer för att göra det möjligt att ta fram undantag även när det är brist på resurser, och programmerare eller typsystemet bör se till att deras kod är undantagssäker . Att sprida ett undantag är mer sannolikt att frigöra resurser än att tilldela dem. Men i objektorienterad programmering kan objektkonstruktion misslyckas, eftersom konstruktionen av ett objekt bör etablera klassen invarianter , som ofta inte är giltiga för varje kombination av konstruktorargument. Således kan konstruktörer ta upp undantag.

Det abstrakta fabriksmönstret är ett sätt att frikoppla en viss implementering av ett objekt från kod för att skapa ett sådant objekt.

Skapande metoder

Sättet att skapa objekt varierar mellan olika språk. I vissa klassbaserade språk är en speciell metod känd som en konstruktor ansvarig för att validera ett objekts tillstånd. Precis som vanliga metoder kan konstruktörer överbelastas för att göra det så att ett objekt kan skapas med olika specificerade attribut. Dessutom är konstruktorn det enda stället att ställa in tillståndet för [ Fel förtydligande behövs] oföränderliga objekt . En kopiakonstruktor är en konstruktor som tar en (enskild) parameter av ett existerande objekt av samma typ som konstruktörens klass, och returnerar en kopia av objektet som skickas som en parameter.

Andra programmeringsspråk, som Objective-C , har klassmetoder, som kan inkludera metoder av konstruktortyp, men är inte begränsade till att bara instansiera objekt.

C++ och Java har kritiserats [ av vem? ] för att inte tillhandahålla namngivna konstruktörer – en konstruktor måste alltid ha samma namn som klassen. Detta kan vara problematiskt om programmeraren vill förse två konstruktörer med samma argumenttyper, t.ex. för att skapa ett punktobjekt antingen från de kartesiska koordinaterna eller från de polära koordinaterna , som båda skulle representeras av två flyttal. Objective-C kan kringgå detta problem genom att programmeraren kan skapa en Point-klass, med initialiseringsmetoder, till exempel +newPointWithX:andY: och +newPointWithR:andTheta: . I C++ kan något liknande göras med statiska medlemsfunktioner.

En konstruktor kan också hänvisa till en funktion som används för att skapa ett värde för en taggad union , särskilt i funktionella språk.

Objekt förstörelse

Det är i allmänhet så att efter att ett objekt har använts tas det bort från minnet för att göra plats för andra program eller objekt att ta objektets plats. Men om det finns tillräckligt med minne eller om ett program har en kort körtid kan det hända att objekt inte förstörs, utan att minnet helt enkelt avallokeras när processen avslutas. I vissa fall består objektdestruktion helt enkelt av att deallokera minnet, särskilt i skräpinsamlade språk, eller om "objektet" faktiskt är en vanlig gammal datastruktur . I andra fall utförs en del arbete före avallokering, särskilt att förstöra medlemsobjekt (i manuell minneshantering), eller ta bort referenser från objektet till andra objekt för att minska referensräkningen (vid referensräkning). Detta kan vara automatiskt, eller så kan en speciell destruktionsmetod anropas på objektet.

I klassbaserade språk med deterministisk objektlivslängd, särskilt C++, är en destruktor en metod som kallas när en instans av en klass raderas, innan minnet avallokeras. I C++ skiljer sig destruktörer från konstruktörer på olika sätt: de kan inte överbelastas, får inte ha några argument, behöver inte underhålla klassinvarianter och kan orsaka programavslutning om de ger undantag.

sopsamlingsspråk kan föremål förstöras när de inte längre kan nås av den löpande koden. I klassbaserade GCed-språk är analogen av destruktörer finalizers , som anropas innan ett objekt skräpsamlas. Dessa skiljer sig i att köra vid en oförutsägbar tidpunkt och i en oförutsägbar ordning, eftersom sophämtning är oförutsägbar och är betydligt mindre använda och mindre komplexa än C++-destruktörer. Exempel på sådana språk inkluderar Java , Python och Ruby .

Att förstöra ett objekt gör att alla referenser till objektet blir ogiltiga, och i manuell minneshantering blir alla befintliga referenser hängande referenser . I sophämtning (både spårning av sophämtning och referensräkning) förstörs objekt endast när det inte finns några referenser till dem, men slutförandet kan skapa nya referenser till objektet, och för att förhindra dinglande referenser inträffar objektets återuppståndelse så att referenserna förblir giltiga .

Exempel

C++

  
 
  
   
         
      
                 


  
  
  


    
  
  


   
  
  


 
  


  
          
      
        

  
  
 class  Foo  {  public  :  // Dessa är konstruktörernas prototypdeklarationer.  Foo  (  int  x  );  Foo  (  int  x  ,  int  y  );  // Överbelastad konstruktör.  Foo  (  konst  Foo  &  gammal  );  // Copy Constructor.  ~  Foo  ();  // Destruktör.  };  Foo  ::  Foo  (  int  x  )  {  // Detta är implementeringen av  // enargumentkonstruktorn.  }  Foo  ::  Foo  (  int  x  ,  int  y  )  {  // Detta är implementeringen av  // två-argumentkonstruktorn.  }  Foo  ::  Foo  (  const  Foo  &  old  )  {  // Detta är implementeringen av  // kopieringskonstruktorn.  }  Foo  ::~  Foo  ()  {  // Detta är implementeringen av förstöraren.  }  int  main  ()  {  Foo  foo  (  14  );  // Ring första konstruktören.  Foo  foo2  (  12  ,  16  );  // Anrop överbelastad konstruktör.  Foo  foo3  (  foo  );  // Anropa kopiekonstruktorn.  // Destructors anropade i baklänges-ordning  // här, automatiskt.  } 

Java

 

      
    
        
        
    

        
    
        
        
    

      
    
        
        
    

        
    
             
              
             
        
    
 class  Foo  {  public  Foo  (  int  x  )  {  // This is the implementation of  // the one-argument constructor  }  public  Foo  (  int  x  ,  int  y  )  {  // This is the implementation of  // the two-argument constructor  }  public  Foo  (  Foo  old  )  {  // Detta är implementeringen av  // copy constructor  }  public  static  void  main  (  String  [ ]  args  )  {  Foo  foo  =  new  Foo  (  14  );  // ring första konstruktören  Foo  foo2  =  new  Foo  (  12  ,  16  );  // anrop överbelastad konstruktör  Foo  foo3  =  ny  Foo  (  foo  );  // ring kopia konstruktorn  // sophämtning sker under täcket och objekt förstörs  }  } 

C#

 

 

     
    
        
        
    

      
    
        
        
    
     
    
        
        
    

        
    
        
        
    
 
      
    
        
        
    
 
        
    
             
             
              
             
    
 namnområde  ObjectLifeTime  ;  class  Foo  {  public  Foo  ()  {  // Detta är implementeringen av  // standardkonstruktor.  }  public  Foo  (  int  x  )  {  // Detta är implementeringen av  // enargumentkonstruktorn.  }  ~  Foo  ()  {  // Detta är implementeringen av  // förstöraren.  }  public  Foo  (  int  x  ,  int  y  )  {  // Detta är implementeringen av  // två-argumentkonstruktorn.  }  public  Foo  (  Foo  old  )  {  // Detta är implementeringen av  // kopieringskonstruktorn.  }  public  static  void  Main  (  sträng  []  args  )  {  var  defaultfoo  =  new  Foo  ();  // Anrop standardkonstruktorn  var  foo  =  new  Foo  (  14  );  // Call first constructor  var  foo2  =  new  Foo  (  12  ,  16  );  // Anrop överbelastad konstruktor  var  foo3  =  new  Foo  (  foo  );  // Anropa kopia konstruktorn  }  } 

Mål-C



 

    
    



      
      


    
    








 
 

     

     


     

     


        

   
   
        


        

   
   
      







   
        
        

   
   
   
   
   
   
    

   

    

    0
 #import <objc/Object.h>  @interface  Punkt  :  Objekt  {  double  x  ;  dubbelt  y  ;  }  //Dessa är klassmetoderna; vi har deklarerat två konstruktorer   +  (  Point  *  )  newWithX:  (  double  )  andY  :  (  double  );  +  (  Punkt  *  )  newWithR:  (  double  )  andTheta  :  (  double  );  //Instansmetoder  -  (  Point  *  )  setFirstCoord:  (  double  );  -  (  Point  *  )  setSecondCoord:  (  double  );  /* Eftersom Point är en underklass till den generiska Object  *-klassen, får vi redan generiska allokerings- och initialiseringsmetoder  *, +alloc och -init. För våra specifika konstruktörer   * kan vi göra dessa från dessa metoder vi har *  ärvt.  */  @end  @implementation  Point  -  (  Point  *  )  setFirstCoord:  (  double  )  new_val  {  x  =  new_val  ;  }  -  (  Point  *  )  setSecondCoord:  (  double  )  new_val  {  y  =  new_val  ;  }  +  (  Point  *  )  newWithX:  (  double  )  x_val  andY:  (  double  )  y_val  {  //Koncis skriven klassmetod för att automatiskt allokera och  //utföra specifik initiering.  returnera  [[[  Point  alloc  ]  setFirstCoord  :  x_val  ]  setSecondCoord  :  y_val  ];  }  +  (  Point  *  )  newWithR:  (  double  )  r_val  andTheta:  (  double  )  theta_val  {  //Istället för att utföra samma sak som ovan, kan vi underhands  //använda samma resultat av den tidigare metoden  returnera  [  Point  newWithX  :  r_val  andY  :  theta_val  ];  }  @end  int  main  (  void  )  {  //Konstruerar två punkter, p och q.  Point  *  p  =  [  Point  newWithX  :  4.0  andY  :  5.0  ];  Point  *  q  =  [  Point  newWithR  :  1.0  and Theta  :  2.28  ];  //...programtext...  //Vi är klara med p, säg, så, frigör det.  //Om p allokerar mer minne åt sig själv, kan behöva  //åsidosätta objektets fria metod för att rekursivt  //frigöra p:s minne. Men så är inte fallet, så vi kan bara   [  p  free  ];  //...mer text...  [  q  gratis  ];  återvända  ;  } 

Objekt Pascal

Relaterade språk: "Delphi", "Free Pascal", "Mac Pascal".

 



   
    
      
      
      
      
    

    
  
     

  
     
     
     
     

  
    

     
       
        
         
      

    

     
  

 

  
    


   

  
    
    

    


    

  
    
    
    

    


     

  
    
    
    
    

    


  

  
    
    
    
    

    


 

  
    



  
    
  
   

 
  
   

  

   

  
       

  

    
   program  Exempel  ;  typ  DimensionEnum  =  (  deUnassigned  ,  de2D  ,  de3D  ,  de4D  )  ;  PointClass  =  klass  privat  Dimension  :  DimensionEnum  ;  public  X  :  Heltal  ;  Y  :  Heltal  ;  Z  :  heltal  ;  T  :  Heltal  ;  public  (* prototyp av konstruktörer *)  konstruktor  Skapa  ()  ;  konstruktor  Skapa  (  AX  ,  AY  :  Heltal  )  ;  konstruktor  Skapa  (  AX  ,  AY  ,  AZ  :  heltal  )  ;  konstruktor  Skapa  (  AX  ,  AY  ,  AZ  ,  ATime  :  Integer  )  ;  konstruktör  CreateCopy  (  APoint  :  PointClass  )  ;  (* prototyp av förstörare *)  destructor  Destroy  ;  slut  ;  konstruktör  PointClass  .  Skapa  ()  ;  börja  // implementering av en generisk, icke-argumentkonstruktor  Self  .  Dimension  :=  deUnassigned  ;  slut  ;  konstruktör  PointClass  .  Skapa  (  AX  ,  AY  :  heltal  )  ;  börja  // implementering av en, 2 argumentkonstruktor  Self  .  X  :=  AX  ;  Y  :=  AY  ;  Själv  .  Dimension  :=  de2D  ;  slut  ;  konstruktör  PointClass  .  Skapa  (  AX  ,  AY  ,  AZ  :  heltal  )  ;  börja  // implementering av en, 3 argument constructor  Self  .  X  :=  AX  ;  Y  :=  AY  ;  Själv  .  X  :=  AZ  ;  Själv  .  Dimension  :=  de3D  ;  slut  ;  konstruktör  PointClass  .  Skapa  (  AX  ,  AY  ,  AZ  ,  ATime  :  Integer  )  ;  börja  // implementering av en, 4 argument constructor  Self  .  X  :=  AX  ;  Y  :=  AY  ;  Själv  .  X  :=  AZ  ;  T  :=  ATime  ;  Själv  .  Dimension  :=  de4D  ;  slut  ;  konstruktör  PointClass  .  CreateCopy  (  APoint  :  PointClass  )  ;  börja  // implementering av en "kopiera" konstruktor  APoint  .  X  :=  AX  ;  APoint  .  Y  :=  AY  ;  APoint  .  X  :=  AZ  ;  APoint  .  T  :=  ATime  ;  Själv  .  Dimension  :=  de4D  ;  slut  ;  förstörare  PointClass  .  PointClass  .  Förstöra  ;  börja  // implementering av ett generiskt, icke-argumentförstörare  Self  .  Dimension  :=  deUnAssigned  ;  slut  ;  var  (* variabel för statisk allokering *)  S  :  PointClass  ;  (* variabel för dynamisk allokering *)  D  :  ^  PointClass  ;  börja  (* av programmet *)  (* objekt livlina med statisk allokering *)  S  .  Skapa  (  5  ,  7  )  ;  (* gör något med "S" *)  S  .  Förstöra  ;  (* objektlivlina med dynamisk allokering *)  D  =  ny  PointClass  ,  Skapa  (  5  ,  7  )  ;  (* gör något med "D" *)  dispose  D  ,  Destroy  ;  slut  .  (* av programmet *) 

Pytonorm

 
         
        

     
        

     
        
        
     
        
        
     
        
        

 
      
    
      klass  Socket  :  def  __init__  (  self  ,  remote_host  :  str  )  ->  Ingen  :  # anslut till fjärrvärd  def  send  (  self  ) :  # Skicka data  def  recv  (  self  ) :  # Receive data  def  close  (  self  ) :  # stäng uttaget  def  __del__  (  self  ):  # __del__ magisk funktion anropas när objektets referensantal är lika med noll  själv  .  close  ()  def  f  ():  socket  =  Socket  (  "example.com"  )  socket  .  skicka  (  "testa"  )  returnera  uttag  .  recv  () 

Socket kommer att stängas vid nästa sophämtningsomgång efter att "f"-funktionen körs och återkommer, eftersom alla referenser till den har gått förlorade.

Se även

Anteckningar