struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
Это обычно для C, но не для C ++.В C ++ это обычно выглядит так:
template<typename T>
struct Node
{
struct Node *next;
T data;
};
T& getLastItem(const Node&);
...
Обратите внимание на важное отличие - версия C имеет другой уровень косвенности для совместного использования реализаций, в то время как версия C ++ не должна этого делать.Это означает, что версия C имеет другое n
динамическое распределение памяти, где n
- количество элементов в списке.Принимая во внимание, что каждое выделение обычно требует получения глобальной блокировки, часто имеет не менее 16 байтов служебной информации на выделение, а также все накладные расходы, которые диспетчер памяти приносит участнику, преимущество версии C ++ не является незначительным, особенно когда вы включаететакие вещи, как локальность кэша в рассмотрении.
Другими словами, для Node<int>
версия C ++ хранит int
, а версия C хранит int *
вместе с динамическим выделением для int
.
Это, конечно, дисконтирование того, что связанный список является ужасающей структурой данных в 90% случаев.
Если вы должны использовать связанный список, и если вы должны использовать динамическое распределение длячлены данных, то ваша идея «заменить указатели на void*
s» не является необоснованной.Однако, если у вас есть доступ к компилятору C ++ 11 (VS2010, последние версии GCC и т. Д.), Вы должны подтвердить, что вы зависите от T
, являющегося типом указателя, используя std::is_pointer
и static_assert
, и вы должны использовать static_cast
, а не приведения в стиле C в ваших методах интерфейса.Приведение в стиле C позволило бы кому-нибудь сделать Node<SomeTypeBiggerThanVoidPtr>
, и оно скомпилировалось бы, но взорвалось во время выполнения.