Метод удаления из моего кругового связанного списка хорошо определен?

Я строю круговой связанный список, и я хотел бы знать, если do_remove Метод хорошо определен. Когда я запускаю программу, она показывает мне, что, тем не менее, я все еще немного сбит с толку, почему мне не нужен виртуальный разрушитель в этом случае.

Виртуальный деструктор нужен только тогда, когда я хочу уничтожить производный класс через его базовый указатель?

Означает ли это, что, понижая базовый класс до производного класса, а затем вызывая деструктор производного класса, он всегда будет вызывать деструктор базового класса?

Могут ли быть возможные утечки в do_remove метод?

PS: мне нужно, чтобы создание и уничтожение объекта было двухэтапным процессом — выделение / вызов конструктора / вызов деструктора / освобождение; вот почему я использую ::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;
}

0

Решение

Виртуальный деструктор нужен только тогда, когда я хочу уничтожить производное
класс через его базовый указатель?

Да. Только если вы удаляете объект с помощью базового указателя (или если вы управляете им с помощью unique_ptr для базы) вам нужен виртуальный деструктор в базе. В других случаях, таких как удаление указателя на большинство производных типов или управление с помощью shared_ptr для base, виртуальный деструктор не требуется.

Означает ли это, что путем перевода базового класса в производный класс,
и затем вызывая деструктор производного класса, он всегда будет вызывать
деструктор базового класса?

Да. Деструктор производного класса необходим для вызова деструкторов (базовых и членских) подобъектов.

Возможны ли утечки в методе do_remove?

Нет, если деструктор TYPE не протекает. Для простоты было бы лучше использовать обычное выражение удаления

    delete node;

вместо того, чтобы писать, что в любом случае требуется сделать

    node->~Node();
::operator delete(node);
1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector