마지막으로 소멸자를 두 번 호출하여 발생하는 매우 이상한 버그를 추적했습니다.shared_ptr을 사용할 때 이상한 이중 소멸자 호출
#include <iostream>
#include <memory>
#include <set>
class cEventSystem {
public:
cEventSystem() {
std::cout << "constructor: " << this << std::endl;
}
~cEventSystem() {
std::cout << "destructor: " << this << std::endl;
}
};
class cSubscriber {
public:
cSubscriber(cEventSystem& eventSystem) : eventSystem(eventSystem) {}
virtual ~cSubscriber() {}
virtual void onEvent() = 0;
protected:
cEventSystem& eventSystem;
};
class cTileBrowser: public cSubscriber {
public:
cTileBrowser(cEventSystem eventSystem) : cSubscriber(eventSystem) {}
void onEvent() {}
};
class cGui: public cSubscriber {
public:
cGui(cEventSystem& eventSystem) : cSubscriber(eventSystem) {
tileBrowser = std::make_shared<cTileBrowser>(eventSystem);
}
void onEvent() {}
std::shared_ptr<cTileBrowser> tileBrowser;
};
int main() {
cEventSystem eventSystem;
cGui gui(eventSystem);
}
출력은 다음과 같습니다 : 여기에 버그를 재현 최소한의 코드는
constructor: 0x7fffffffe67f
destructor: 0x7fffffffe2df
destructor: 0x7fffffffe67f
첫 번째 소멸자가 원하지 않는과가에 건설되지 않은 다른 객체라고 볼 수 있듯이 모두 (주소는 다르다). 그러나 내 실제 코드에서 주소는 충분히 가깝고 이벤트 시스템에있는 컨테이너를 손상시킨다.
디버깅은 해당 소멸자 호출을 발생시키는 make_shared임을 보여줍니다.
불필요한 소멸자 전화가 발생하는 이유는 무엇이며 어떻게 제거합니까? g ++ 4.7을 C++ 11 플래그와 함께 사용합니다.
문제는 원치 않는 소멸자 호출 일반적으로 (시간의 90 %) 세그먼테이션 폴트 (segfault)를 발생 내 실제 코드 내 이벤트 시스템 컨테이너를 손상한다는 것입니다,하지만 거의 그것을 손상하지하지 않고, 모든 것이 작동합니다.
남자, 당신은 영웅입니다, 제 실제 코드에서 작동합니다! 하지만 왜 임시 복사본이 너무 안전하지 않아서 메모리에있는 내 데이터가 손상 될 수 있습니까? 나는 거의 항상 참고 문헌 (이 것은 실수였다.)을 통과하지만 적어도 나에게는 이상하게 보인다. – user1873947
@ user1873947, 복사 생성자가 컴파일러로 생성되었으므로 아마 잘못된 것입니다. 예를 들어 포인터의 복사본을 만들고 소멸자가 삭제하면 원본 개체에 매달린 포인터가 남아 있습니다. –
@Mark Ransom 그게 전부입니다. 내 실제 코드에는 포인터 집합이 있습니다. – user1873947