我发送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();
问题在于,在这种情况下,应用程序在删除回调中的用户时会崩溃,因为它已被删除。另一个问题是回调删除了用户,但user
中的main
指针仍然指向某个地址(悬空指针),所以我再次尝试删除它。
我不确定在这种情况下管理内存的最佳方法是什么。我有zombie
,因为有些情况下我不希望回调删除用户。
答案 0 :(得分: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
中。这样,如果您的主代码想要销毁用户对象,它只需调用user.reset()
即可。然后,如果回调尝试使用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
}