2012-05-22 87 views
0

我正在發送一個HTTP請求來保存/更新服務器上的數據。該請求是異步完成的,並在完成時調用回調函數。一切正常,除了有時候,應用程序在回調中崩潰。刪除回調函數中的對象

這是我在做什麼:

user = new User(); 
user->saveOnServer(); 
user->zombie = true; // Mark the user that it needs to be deleted in the callback. 

User,我有一個saveOnServer()方法:

void User::saveOnServer(){ 
    Request *request = new Request(); 

    // Send request to the server and register the callback. 
    request ->setCallback(&userCallback, (void*)this); 
} 

回調:

void userCallback(void *data){ 
    User *user = (User*)data; 

    // Do something here. 
    // Delete user if it's a zombie. 
    if(user->zombie) 
     delete user; 
} 

有時候,我需要在向服務器發送請求後創建一個新用戶:

user = new User(); 
user->saveOnServer(); 
user->zombie = true; 
// Some code comes here. 
if(user) 
    delete user; 
user = new User(); 

問題是,在這種情況下,應用程序在刪除回調中的用戶時會崩潰,因爲它已被刪除。另一個問題是,回調刪除用戶,但main指針user仍然指向某個地址(懸掛指針),所以我再次嘗試刪除它。

我不確定在這種情況下管理內存的最佳方式是什麼。我有zombie,因爲有些情況下我不希望回調刪除用戶。

+0

爲什麼你會想要一臺服務器刪除我想知道的客戶端分配的對象? – AJG85

+0

服務器不刪除任何內容。客戶端在請求結束後有一個回調來刪除對象。 – umair

+0

當處理請求完成時,服務器不會調用回調嗎?非常有趣...我只是想跳到這一點。在回調中不應該有原始指針,應該不需要在任何地方調用delete,並且在使用所有權已傳遞給異步調用的對象之前,需要臨界區和等待條件。 – AJG85

回答

3

一旦你調用了殭屍用戶的saveOnServer,請求就是該用戶對象的有效「擁有者」。不要自己釋放它,因爲還有其他東西仍然打算使用它,並在以後刪除它。

事實上,如果服務器操作可以異步返回,那麼用戶對象可能隨時被銷燬。您應該從其他代碼中完全停止使用它。你給了那個對象請求的控制,並且必須停止使用它從其他地方:

user = new User(); 
user->zombie = true; // set *before* transferring ownership to server 
user->saveOnServer(); 
user = NULL; 
//some code comes here 
user = new User(); 

如果你不想請求使用該對象了,那麼你就需要提供一些設施用於「取消」保存服務器操作,以便它不使用該對象。


另一種選擇是使用智能指針。在您的主代碼中,將對象存儲在shared_ptr中。在請求對象中,將其存儲在weak_ptr中。這樣,如果您的主代碼想要銷燬用戶對象,則可以簡單地調用​​。然後,如果回調嘗試使用weak_ptr,則會發現指向的對象不再可用。當使用智能指針時,函數都不應該使用delete。指針對象將爲您管理用戶的生命週期。

shared_ptr<User> user = make_shared<User>() 
user->saveOnServer(); 
//some code comes here 
user.reset(new User()); 

saveOnServer功能,使用shared_from_this創建weak_ptr對象:

void User::saveOnServer(){ 
    Request *request = new Request(); 

    //send request on server and register the callback 
    weak_ptr<User> self(shared_from_this()); 
    request ->setCallback(&userCallback, self); 
} 

在回調,使用weak_ptr

void userCallback(weak_ptr<User> data){ 
    shared_ptr<User) user = data.lock(); 
    if (!user) 
    return; 

    //do something here 
} 
+0

問題是我需要重新使用用戶指針來創建新用戶。我一定會看看智能指針。謝謝 – umair

+1

然後繼續並重新使用它。我在這裏寫的任何東西都排除了這一點。您可以儘可能多地重用*變量*。但是如果你已經轉移了* object *的所有權,那麼你不能繼續使用它。我在第一個代碼示例中通過調用'user-> saveOnServer()'後立即分配'user = NULL'來說明。注意,稍後變量會被'user = new User()'重新賦值,但是之間沒有任何內容試圖解引用'user',因爲該代碼不再控制它;它屬於請求對象。 –

+0

如果user-> zombie = true,那麼你的解決方案可以很好地工作,但如果我不想回叫來刪除它並設置user-> zombie = false,那麼當我創建一個新用戶或設置它時,回調並不會刪除它並且內存會丟失爲NULL。有無論如何檢查回調是否已經刪除用戶,如果沒有,那麼我檢查殭屍。如果爲false,則在創建新用戶之前將其刪除。 – umair