Можно ли принудительно установить непрерывную границу размещения в шаблоне C ++? - PullRequest
0 голосов
/ 13 сентября 2010

Простой пример:

template <class P> class MyT
{
    struct Item
    {
    public:
        Item() {}
        P *pData;
        Item *next;
    };
    Item *head;
public:
    ...adding etc..
    P* operator [](int index)
    {
       See question below:
    }
};

Могу ли я каким-то образом убедиться, что элементы 'расположены так, что я могу рассчитать смещение следующим образом: (@Steve :) Может быть, здесь не так ясно; мне нужен быстрый и простой способ добраться до предмета без повторения 10000 следующих.

Item *pi = head + (sizeof(Item) * (index - 1));

A (яснее?) Объяснение того, что я имею в виду

Ответы [ 5 ]

1 голос
/ 14 сентября 2010

«Границы памяти» можно принудительно задать с помощью специальных ключевых слов gcc

http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributes

посмотрите на "выравнивание"

1 голос
/ 13 сентября 2010

Я думаю, что вам нужно это std :: list или std :: vector.

Однако то, что вы пытаетесь, сработало бы, если бы вы выделили последовательную память для Items и head указывает на начало вместе смодификация, предложенная Yossarian.

Вы можете предварительно выделить при инициализации, если этот предел будет превышен, выделите больше и скопируйте свое содержимое в эту область, освобождая существующее.упакованы для вас в стандартные контейнеры.

1 голос
/ 13 сентября 2010

Зависит от того, что вы подразумеваете под "и т. Д.", Под "добавлением и т. Д.".

Если «etc» включает в себя «удаление», то у вас возникает очевидная проблема: если вы удалите что-то в середине списка, то для поддержания индексации вам придется сдвигать все после него вниз, что означает обновление всех next указатели.

Я думаю, что вы, возможно, слишком упростили свой пример. Если вам требуется непрерывное хранение, используйте вектор (либо P, либо Item, если в Item есть что-то полезное, что вы удалили). Если у вас есть непрерывное хранилище, то нет смысла иметь указатель next, поскольку вы можете просто вычислить его в Item, добавив 1 к this (а затем проверить границу, чтобы убедиться, что вы не достигли конец).

Если вам абсолютно необходимо общедоступное поле указателя next, потому что оно является частью какого-то интерфейса, который вы реализуете, и который вы не можете изменить, вы можете обновить его в конструкторе копирования и operator= для Item, и интерфейс лучше запретить клиентам писать в него.

Невозможно указать распределителю памяти выделять непрерывное хранилище для отдельных выделений, если вы об этом и просите. Как это вообще сработает? Что если, когда вы приходите выделять, «следующий» адрес уже занят? Что если распределитель налагает некоторые накладные расходы для своих собственных управляющих структур (как это делают почти все распределители общего назначения), так что для выделения Item требуется более sizeof(Item) байтов? Вы можете какое-то время получить желаемое поведение с помощью фиксированного размера распределителя , но в конечном итоге ему понадобится новый блок или вы удалите что-то, и связь больше не будет сохраняться.

0 голосов
/ 15 сентября 2010

Если я правильно понимаю ваш вопрос, вам нужно переопределить operator new для Item и иметь распределитель, заранее выделивший достаточно памяти для хранения всех Item с, которые вам когда-либо понадобятся (что невозможно в общемслучай, но может быть возможным в вашем конкретном сценарии).Затем всякий раз, когда Item обновляется, распределитель возвращает следующий слот в предварительно выделенном блоке.

Все это выглядит нереально, и простым решением было бы использовать std::vector.

0 голосов
/ 13 сентября 2010
Item* pi = (head + (index - 1));

делает работу.Кстати, вы уверены, что хотите это сделать?struct Item выглядит как структура связанного списка (содержит next).

...