몇 가지 코드가 있습니다.
class LowLevelObject {
public:
void* variable;
};
// internal, can't get access, erase, push. just exists somewhere
std::list<LowLevelObject*> low_level_objects_list;
class HighLevelObject {
public:
LowLevelObject* low_level_object;
};
// my list of objects
std::list<HighLevelObject*> high_level_objects_list;
// some callback which notifies that LowLevelObject* added to low_level_objects_list.
void CallbackAttachLowLevelObject(LowLevelObject* low_level_object) {
HighLevelObject* high_level_object = new HighLevelObject;
high_level_object->low_level_object = low_level_object;
low_level_object->variable = high_level_object;
high_level_objects_list.push_back(high_level_object);
}
void CallbackDetachLowLevelObject(LowLevelObject* low_level_object) {
// how to delete my HighLevelObject* from high_level_objects_list?
// HighLevelObject* address in field `variable` of LowLevelObject.
}
라이브러리에 정의 된 저수준 개체가 있으며 variable
사용자가 사용할 필드 가 포함되어 있습니다 .
이 varaible
포인터를 HighLevelObject
내 코드에서 설정했습니다 . 라이브러리의 목록에서
추가 및 제거시 콜백을 설정할 수 있습니다 LowLevelObject
.
하지만 HighLevelObject
내 개체 목록에서 어떻게 제거 할 수 있습니까?
물론 전체 목록을 반복하고 포인터로 개체별로 찾아 제거 할 수 있다는 것을 알고 있지만 먼 길입니다.
목록에는 많은 개체가 포함될 수 있습니다.
미리 감사드립니다!
설정은 포인터를 반복자로 변환하는 것이 일정한 시간 작업 인 솔루션을 찾는 데 적합합니다. Boost.Intrusive는이 기능을 제공합니다. 그래도 코드를 변경해야합니다. 캡슐화에 대해주의하지 않았다면 이러한 변경 사항이 중요 할 수 있습니다. A boost::intrusive::list
는 기능적으로와 유사 std::list
하지만 데이터 구조를 약간 변경해야합니다. 이 옵션은 모든 사람에게 적합하지 않을 수 있습니다.
Boost.Intrusive의 또 다른 기능은 때때로 포인터를 반복자로 명시 적으로 변환 할 필요가 없다는 것입니다. 자동 연결 해제를 활성화하면 목록에서 실제 삭제가 소멸자의 뒤에서 발생합니다. 하지만 일정 시간 내에 목록의 크기를 가져와야하는 경우에는 좋은 옵션이 아닙니다. (질문의 어떤 것도 목록의 크기를 가져 오는 것이 필요하다는 것을 나타내지 않으므로이 접근 방식을 계속 진행할 것입니다.)
객체의 컨테이너가있는 경우 침입 목록에 대한 문서를 통해 작업 할 수 있습니다. 그러나 포인터를 사용하면 변환이 잠재적으로 혼란 스러울 수 있으므로 설정을 살펴 보겠습니다. 설정은 다음으로 시작됩니다.
#include <boost/intrusive/list.hpp>
// Shorten the needed boost namespace.
namespace bi = boost::intrusive;
상위 수준 개체 목록에는 포인터가 포함되어 있으므로 보조 구조가 필요합니다. Boost에서 제공하는 클래스에서 파생되는 포인터의 양이 필요합니다. (에서 생성 된 객체가에서 CallbackAttachLowLevelObject()
소멸되어야 한다고 가정하겠습니다 CallbackDetachLowLevelObject()
. 따라서 원시 포인터를 스마트 포인터로 변경했습니다.)
#include <memory>
#include <utility>
// The auxiliary structure that will be stored in the high level list:
// The hook supplies the intrusive infrastructure.
// The link_mode enables auto-unlinking.
class ListEntry : public bi::list_base_hook< bi::link_mode<bi::auto_unlink> >
{
public:
// The expected way to construct this.
explicit ListEntry(std::unique_ptr<HighLevelObject> && p) : ptr(std::move(p)) {}
// Another option would be to forward parameters for constructing HighLevelObject,
// and have the constructor call make_unique. I'll leave that as an exercise.
// Make this class look like a pointer to HighLevelObject.
const std::unique_ptr<HighLevelObject> & operator->() const { return ptr; }
HighLevelObject& operator*() const { return *ptr; }
private:
std::unique_ptr<HighLevelObject> ptr;
};
목록의 정의는 다음과 같습니다. size()
자동 연결 해제를 허용하려면 일정하지 않은 시간을 지정해야합니다 .
bi::list<ListEntry, bi::constant_time_size<false>> high_level_objects_list;
이러한 변경을 위해서는 "attach"콜백을 약간 변경해야합니다. "detach"콜백으로 넘어 가기 전에 그것들을 제시하겠습니다.
// Callback that notifies when LowLevelObject* is added to low_level_objects_list.
void CallbackAttachLowLevelObject(LowLevelObject* low_level_object) {
// Dynamically allocate the entry, in addition to allocating the high level object.
ListEntry * entry = new ListEntry(std::make_unique<HighLevelObject>());
(*entry)->low_level_object = low_level_object; // Double indirection needed here.
low_level_object->variable = entry;
high_level_objects_list.push_back(*entry); // Intentional indirection here!
}
이 준비 작업을 통해 RAII에 적합한 것처럼 소멸자에서 정리가 이루어집니다. "분리"는 프로세스를 시작하기 만하면됩니다. 한 줄이면 충분합니다.
void CallbackDetachLowLevelObject(LowLevelObject* low_level_object) {
delete static_cast<ListEntry *>(low_level_object->variable);
}
높은 수준의 목록이 개체가 아닌 포인터 인 이유를 설명하기에 충분한 컨텍스트가 (적절하게) 없습니다. 한 가지 잠재적 인 이유는 높은 수준의 개체가 다형성이고 포인터를 사용하면 슬라이싱을 피할 수 있기 때문입니다. 이 경우 (또는 포인터를 사용할 적절한 이유가없는 경우) 기존 코드에 미치는 영향을 줄이면서 침입 목록을 디자인 할 수 있습니다. 여기서주의 할 점 HighLevelObject
은 변경 이 필요하다는 것입니다.
초기 설정은 이전과 동일합니다.
#include <boost/intrusive/list.hpp>
// Shorten the needed boost namespace.
namespace bi = boost::intrusive;
다음으로 HighLevelObject
후크에서 파생됩니다.
class HighLevelObject : public bi::list_base_hook< bi::link_mode<bi::auto_unlink> > {
public:
LowLevelObject* low_level_object;
};
이 상황에서 목록은 HighLevelObject
포인터 나 포인터 스탠드 인이 아닌 s입니다.
bi::list<HighLevelObject, bi::constant_time_size<false>> high_level_objects_list;
"첨부"콜백은 거의 문제의 내용으로 되돌아갑니다. 이 함수의 한 가지 변경 사항은 객체 자체가 포인터가 아니라 목록으로 푸시된다는 것입니다. 이것이 슬라이싱이 문제가되지 않는 이유입니다. 목록에 추가되는 복사본이 아니라 개체 자체입니다.
high_level_objects_list.push_back(*high_level_object); // Intentional indirection!
나머지 코드는 그대로 작동 할 수 있습니다. 우리는 다시 한 줄짜리 "분리"콜백이 필요합니다.
void CallbackDetachLowLevelObject(LowLevelObject* low_level_object) {
delete static_cast<HighLevelObject *>(low_level_object->variable);
}
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다