2012-09-07 111 views
1

請考慮以下簡單代碼。通過引用傳遞對象而不通過指針傳遞的對象的作用域

struct test 
    { 
     test(int n):numelements(n){ arr = new int[numelements] } 

     int numelements; 
     int* arr; 

     ~test() 
     { 
      delete[] arr; 
     } 
    } 

    void foo_ref(test& x,n) 
    { 
     // set first n elements of the array x.arr to random numbers 
    } 

    void foo_ptr(test* x,n) 
    { 
     // set first n elements of the array x->arr to random numbers 
    } 

    int main(void) 
    { 
    test mystruct(1000000); 
    foo_ref(mystruct,20); 
    // foo_ptr(&mystruct,20); 


    return 0; 
    } 

在上面的代碼,foo_reffoo_ptr上 執行完全相同的操作是指即該對象。 mystruct。但是,foo_ref通過引用 和foo_ptr通過指針傳遞對象。

在這兩種情況下其中是被調用的對象的析構函數?我知道這個問題的標準答案始終是「當一個對象的範圍結束」

但是考慮通過引用傳遞的情況。在foo_ref 的內部,mystruct具有該函數的範圍。所以在功能foo_ref的末尾不會調用該對象的析構函數嗎?

也許我的困惑與某物的範圍的理解做。 請讓我知道我在我的推理中犯錯的地方。

+2

你知道':包含numElements(N),編曲(新INT [包含numElements])'是有效的,也只要'numelements'在你的類中的'arr'之前聲明。 – chris

+1

讓我們看看代碼foo_ref – Mark

+0

@標記見編輯。他們只是函數,說初始化一些元素或任何 – smilingbuddha

回答

3

我沒有看到任何const引用在這裏,因此答案是「在引用和指針之間對象的生命沒有什麼不同」。

const引用勢必臨時表達式有延長臨時對象壽命的特殊規則,但這並不適用於你的代碼。

您的困惑可能源自於a statement made in a very popular FAQ,它沿着「參考是被引用的對象」的方向行事。正如你所看到的,這是不正確的。引用是從它引用的對象分開,每個人都有自己的生命週期(這是非常難得一見這個做得正確,但比對象的生存期延長較長它是參考的壽命甚至法律)

+0

謝謝!我的印象是,當引用超出範圍時,引用的析構函數(因此對象本身)被調用,這將導致內存被釋放。所以通過你的回答,我認爲這種說法是錯誤的。 – smilingbuddha

+0

因此,當引用的析構函數被稱爲引擎蓋下發生了什麼?我認爲與它所指的對象的析構函數完全沒有關係? – smilingbuddha

+0

沒有這樣的東西作爲參考的析構函數。 *對象*具有析構函數,而引用只是引用對象的一種方式。如果某個地方有某個對象的引用,那麼該對象何時/如何被銷燬就沒有影響。也許你把引用與*引用計數*混淆了,這是一個非常不同的事情。 – Oktalist

1

foo_ref將有一個參數,並且它是具有該函數範圍的參數。無論是指針還是引用,都不會對刪除mystruct有任何影響。

在你的價值,則副本會在函數結束時被銷燬傳遞結構的情況。如果你做了一些愚蠢的事情,比如引用副本中的相同arr,那麼當原始結構仍在使用時,你可能會意外刪除arr。在這種情況下,您可能想使用共享指針來跟蹤arr使用的內存,而不是手動刪除它。

1

在示例代碼中,mystruct的析構函數在main的末尾被調用。

指針當指針超出範圍時,指向的對象不會發生任何反應。對象的生命週期保持指針從不存在的狀態。當然有一個重要的細節:由new/new[]創建的對象存在,直到它們是delete d/delete[] d,並且由malloc分配的存儲器一直存在,直到它的free d。

參考文獻引用只不過是現有對象的附加名稱。除了指向臨時對象的const引用外,引用的生命週期不會影響被引用對象的生命週期;當對象超出範圍正常時,調用析構函數(const對臨時對象的引用會使臨時存活,直到const引用超出範圍)。

Using the term "object" is a simplification,指針或引用真的指向內存;它不以任何方式「追蹤」實際對象。例如,可以在指針超出範圍之前銷燬指向的對象,或者在參考超出範圍之前銷燬正在引用的對象。這些無效的指針/引用被稱爲 「懸擺指針」 及 「晃來晃去參考」:

int* i = new int(5); 
int& j = *i; 
delete i; 

// i is now a dangling pointer, and j is now a dangling reference 
+0

引用實際上是內存位置的名稱,而不是對象。我更徹底地解釋了[這裏](http://stackoverflow.com/a/4715888/103167)。 –

+0

@ BenVoigt謝謝。我已經添加了該鏈接的段落。而且,我承認我沒有想過創建懸掛引用的方法。 –

+1

我甚至沒有談論懸掛引用。在與舊的對象相同的內存中創建新對象是合法的,只要類型匹配,現有引用可以與新對象正常工作。 –

相關問題