2012-05-22 3 views
0

서버의 데이터를 저장/업데이트하기 위해 HTTP 요청을 보내고 있습니다. 요청은 비동기 적으로 이루어지고 완료되면 콜백 함수가 호출됩니다. 모든 경우는 예외적 인 경우를 제외하고는 가끔씩 응용 프로그램이 콜백에서 충돌합니다. 콜백 함수의 개체 삭제

내가 뭐하는 거지입니다 :

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에서

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

, 나는 saveOnServer() 방법을 서버에 요청을 보낸 후 새 사용자를 만드십시오.

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

그런 경우에는 이미 삭제 된 콜백으로 사용자를 삭제할 때 응용 프로그램이 충돌합니다. 또 다른 문제는 콜백이 사용자를 삭제하지만 main에있는 user 포인터가 여전히 일부 주소 (매달린 포인터)를 가리키고 있으므로 다시 삭제하려고한다는 것입니다.

이 경우 메모리를 관리하는 가장 좋은 방법은 무엇인지 모르겠습니다. 나는 zombie을 가지고 있습니다. 왜냐하면 콜백이 사용자를 삭제하기를 원치 않을 때가 있기 때문입니다.

+0

왜 당신이 서버에 원하는 것 : 콜백에서

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 것을 사용 클라이언트가 할당 한 객체를 삭제할까? – 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(); 

을 더 이상 객체를 사용하는 요청을하지 않으려면, 당신은 몇 가지 기능을 제공해야 서 v 저장 (save-on-server) 조치가 오브젝트를 사용하지 않도록 "취소"합니다.


또 다른 옵션은 스마트 포인터를 사용하는 것입니다. 주 코드에서 shared_ptr에 개체를 저장하십시오. 요청 개체에서 weak_ptr에 저장합니다. 그렇게하면 주 코드가 사용자 객체를 파괴하려고 할 때 간단히 user.reset()을 호출 할 수 있습니다. 그런 다음 콜백이 weak_ptr을 사용하려고 시도하면 지적 된 객체를 더 이상 사용할 수 없다는 것을 알게됩니다. 스마트 포인터를 사용하는 경우 함수는 delete을 사용해야합니다. 포인터 개체는 사용자의 수명을 관리합니다.saveOnServer 기능에

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

, 객체에 weak_ptr 만들 shared_from_this를 사용

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

사용자 -> zombie = true 인 경우 솔루션이 완벽하게 작동하지만 콜백을 삭제하고 사용자 -> zombie = false를 설정하지 않으면 콜백이 삭제되지 않고 새 사용자를 만들거나 설정하면 메모리가 손실됩니다 NULL로 설정합니다. 어쨌든 콜백이 사용자를 삭제했는지 확인한 다음에 내가 좀비를 확인했는지 확인합니다. false이면 새 사용자를 만들기 전에 삭제합니다. – umair