2016-09-23 47 views
1

我想了解德爾福如何處理任務。我有一個被稱爲GlobalConnTADoConnection)全球連接...德爾福:參考VS副本的TADoConnection變量分配

我已經使得使用變量數據庫調用的函數傳遞參數:使用MakeDbCall

function MakeDBCall(AConnection : TAdoConnection) 
var LocalConn : TAdoConn; 
begin 
    LocalConn := TAdoConnection.Create(nil); 
    try 
     LocalConn := AConnection 
     ///create the table and perform action using the LocalConn 
    finally 
     LocalConn.free;  
    end; 
end; 

的調用將進行(GlobalConn );

  1. LocalConn := AConnection(函數內部)實際發生了什麼?引用計數是增加還是分配給局部變量的新副本?

  2. 釋放LocalConn影響GlobalConn

  3. 理想情況下,我認爲製作副本比採取連接字符串和分配給局部變量並打開...更好(更快)這是一個正確的推定嗎?

  4. 這是否與Delphi 7和XE7-Xe10不同?

感謝

+0

你爲什麼這樣做,而不是隻使用AConnection本身?您對TAdoConnection.Create的調用會在堆上創建一個新實例。通過將LocalConn分配給AConnection,然後通過LocalConn.Free有效地調用AConnection上的Free,可以有效地放棄這一點。因此,當程序退出時,您已經釋放了錯誤的對象,並通過丟棄所創建的TAdoConnection對象來創建內存泄漏。 – MartynA

+1

它不會像你想像的那樣工作,而是用全局覆蓋局部變量(並因此泄漏本地創建的連接),最後釋放全局變量,導致下次打算使用AV時全球變... – whosrdaddy

+0

@whosrdaddy:好吧! – MartynA

回答

3

您的代碼不會做你認爲它。我已經提出了一些評論,試圖解釋到底發生了什麼。

function MakeDBCall(AConnection : TAdoConnection) 
var 
    LocalConn : TAdoConn; 
begin 
    // This creates a brand new ADO connection. 
    LocalConn := TAdoConnection.Create(nil); 
    try 
    // This line discards the connection you've just created, 
    // orphaning it (leaking the memory), and sets LocalConn 
    // to point to the object passed in as AConnection. 
    LocalConn := AConnection 

    ///create the table and perform action using the LocalConn 
    finally 
    // This line frees AConnection, making your global variable invalid 
    LocalConn.free;  
    end; 
end; 

所以對付你直接問的問題:

  1. 居然會發生什麼事時LocalConn:= AConnection(在函數內部)?引用計數是增加還是分配給局部變量的新副本?

以上都不是。

該分配放棄了您剛剛創建的全新連接,泄漏了分配的內存,並且LocalConn成爲指向AConnection的新變量,而不是副本。 TADOConnection不是一個接口,因此不受引用計數的限制。沒有分配新副本 - LocalConn只是另一個指向您傳遞給函數的連接實例的變量。

  1. 釋放LocalConn是否影響GlobalConn?

是的。它釋放了AConnection,使其對它的任何引用無效,大概是您的全局連接實例。 (它對你使用TADOConnection.Create(nil)創建的本地連接沒有任何影響;該內存被泄露,因爲你丟棄了可以用來釋放它的唯一引用。

  • 理想我假定製作副本是比服用連接字符串和分配給局部變量和開口更好(較快)...這是一個正確推定?
  • 它可能是,如果事實上你做一個副本,但你不是。

    1. 這是否與Delphi 7和XE7-Xe10不同?

    號我上面指出的是從V1起與VCL和Windows打交道時,德爾福的每個版本相同。 (移動FMX改變了一些東西,但它不會改變你仍然錯誤地釋放全局對象的事實。)

    如果TADOConnection實際上實現了Assign方法,則可以使用它。然而,從文件中可以看出,它是否已經實施;該文檔鏈接到TPersistent.Assign。您可以查看您實際使用的Delphi版本的源代碼(我沒有在此筆記本電腦上安裝D2007)以查看它是否已實施。如果是這樣,你可以使用這樣的東西:

    LocalConn := TADOConnection.Create(nil); 
    try 
        LocalConn.Assign(AConnection); 
        // Use LocalConn 
    finally 
        LocalConn.Free; // Frees the local copy 
    end; 
    
    +0

    感謝您的信息和建議。我的困惑是基於沒有意識到使用賦值「操作符」時會發生什麼。這是一個鏈接到Embarcadero人加入我的理解:http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Classes_TPersistent_Assign.html。 –