순환 링크 된 목록을 작성 중이며 do_remove
메서드가 잘 정의되어 있는지 알고 싶습니다. 내가 프로그램을 실행할 때, 그러나 나는 이것이 가상 소멸자를 왜 필요로하지 않는지 조금 아직도 혼란 스럽다.순환 링크 된 목록의 제거 방법이 잘 정의되어 있습니까?
가상 소멸자는 기본 포인터를 통해 파생 클래스를 제거하려는 경우에만 필요합니까?
기본 클래스를 파생 클래스로 다운 캐스팅 한 다음 파생 클래스 소멸자를 호출하면 기본 클래스 소멸자가 항상 호출됩니다.
do_remove
메서드에서 누수가 발생할 수 있습니까?
추신 : 두 단계 프로세스 - 생성자 호출/destructor/deallocation에 대한 호출에 대한 할당/호출이 필요합니다. 그래서 나는 당분간 ::operator new
을 사용하고있다.
#include <iostream>
struct NodeBase {
NodeBase * previous;
NodeBase * next;
NodeBase() noexcept
: previous(this)
, next(this) {
}
NodeBase(NodeBase * const previous, NodeBase * const next) noexcept
: previous(previous)
, next(next) {
}
~NodeBase() {
std::puts("~NodeBase()");
}
};
template <typename TYPE>
struct Node : NodeBase {
TYPE data;
template <typename ...ARGUMENTS>
Node(NodeBase * const previous, NodeBase * const next, ARGUMENTS && ...arguments)
: NodeBase(previous, next)
, data(std::forward<ARGUMENTS>(arguments)...) {
previous->next = this;
next->previous = this;
}
~Node() {
std::puts("~Node()");
}
};
template <typename TYPE>
class List {
using Node = Node<TYPE>;
int64_t this_length;
NodeBase this_sentinel;
Node * as_node(NodeBase * const input) noexcept {
return static_cast<Node * const>(input);
}
Node const * as_node(NodeBase const * const input) const noexcept {
return static_cast<Node const * const>(input);
}
template <typename ...ARGUMENTS>
List & do_insert(NodeBase * const node, ARGUMENTS && ...arguments) {
void * const address = ::operator new(sizeof(Node));
try {
new (address) Node(node->previous, node, std::forward<ARGUMENTS>(arguments)...);
++this_length;
return *this;
} catch (...) {
::operator delete(address);
throw;
}
}
// Is this method well defined?
List & do_remove(NodeBase * input) noexcept {
Node * const node = as_node(input);
input->previous->next = input->next;
input->next->previous = input->previous;
node->~Node();
::operator delete(node);
--this_length;
return *this;
}
public:
List()
: this_length(0)
, this_sentinel() {
}
~List() {
std::puts("~List()");
while (this_length) {
pop();
}
}
TYPE & head() noexcept {
return as_node(this_sentinel.next)->data;
}
TYPE const & head() const noexcept {
return as_node(this_sentinel.next)->data;
}
TYPE & last() noexcept {
return as_node(this_sentinel.previous)->data;
}
TYPE const & last() const noexcept {
return as_node(this_sentinel.previous)->data;
}
template <typename ...ARGUMENTS>
List & push(ARGUMENTS && ...arguments) {
return do_insert(this_sentinel.next, std::forward<ARGUMENTS>(arguments)...);
}
List & pop() noexcept {
return do_remove(this_sentinel.next);
}
};
int main() {
List<int> list;
list.push(5).push(7).push(3);
std::cout << list.head() << std::endl;
std::cout << list.last() << std::endl;
return 0;
}
을 할 필요가 무엇을 쓰는 일반 삭제 표현을
를 사용하는 것이 좋습니다 것, 그건 m 분리 파괴. 나중에 새로운 할당자를 수용하도록 코드를 변경하는 것이 더 쉽습니다. 감사 :) –