Страницы

Поиск по вопросам

вторник, 25 декабря 2018 г.

C# Проблема с указателями при создании связного списка

Добрый день! Требуется создать связный список объектов структуры, в котором текущий элемент должен указывать на следующий, последний - на null. На C++ когда делал подобное - проблем не возникло. На C# первый элемент создается без проблем. Но второй создается с тем-же адресом! Как это исправить?
// Структура объектов очереди struct QueueItem { public int Value; public unsafe QueueItem* Next;
public unsafe QueueItem(int value) : this() { Value = value; Next = null; } }
class QueueWithMinStats { private unsafe QueueItem* _first; private unsafe QueueItem* _last; public unsafe QueueWithMinStats() { _first = null; _last = null; }
// Добавить в очередь значение public unsafe void Enqueue(int value) { // Проблема тут!!! var newItem = new QueueItem(value); var newItemLink = &newItem;
if (_first == null) // Если вводимый элемент - первый _first = newItemLink; else _last->Next = newItemLink;
_last = newItemLink;
} }


Ответ

Применительно к структуре, оператор new не выделяет память, а лишь вызывает конструктор. Сама структура каждый раз создается на стеке в одном и том же месте - неудивительно что указатели одинаковы.
Для того, чтобы структура "перенеслась" в кучу - надо кастануть ее к типу object (эта операция называется упаковкой). Но у упакованной структуры получить адрес средствами языка - не так-то и просто...
Поэтому предлагаю вам сделать все по-другому.
Во-первых, замените структуру на класс (значимый тип на ссылочный). Во-вторых, уберите указатели: для ссылочных типов они не нужны.
Вместе с другими, не столь критичными, исправлениями, получится как-то так:
class QueueWithMinStats { class QueueItem // я перенес этот класс внутрь, потому что за пределами реализации очереди он никому не должен быть интересен { public int Value; public QueueItem Next;
public QueueItem(int value) { Value = value; // Next инициализаровать не надо - поля классов инициализируются значениями по умолчанию автоматически } }
private QueueItem _first; private QueueItem _last;
// Конструктор пока не нужен
public void Enqueue(int value) { // Проблемы больше нет!!! var newItem = new QueueItem(value); // Переменная newItemLink больше не нужна - потому что QueueItem - это ссылочный тип
if (_first == null) // Если вводимый элемент - первый _first = newItem; else _last.Next = newItem;
_last = newItem; } }

Комментариев нет:

Отправить комментарий