Подтвердить что ты не робот

Std::string без свободного распределения памяти хранилища

У меня вопрос, очень похожий на

Как выделить std::string в стеке с помощью реализации строки glibc?

но я думаю, что стоит снова спросить.

Я хочу std::string с локальным хранилищем, которое переполняется в свободное хранилище. std::basic_string предоставляет распределитель в качестве параметра шаблона, поэтому кажется, что нужно сделать, чтобы написать распределитель с локальным хранилищем и использовать его для параметризации basic_string, например:

std::basic_string<
char, 
std::char_traits<char>, 
inline_allocator<char, 10> 
> 
x("test");

Я попытался написать класс inline_allocator, который будет работать так, как вы ожидали: он хранит 10 байт для хранения, а если basic_string требуется более 10 байтов, то он вызывает ::operator new(). Я не мог заставить его работать. В ходе выполнения вышеуказанной строки кода моя стандартная строковая библиотека GCC 4.5 вызывает конструктор копирования для inline_allocator 4 раза. Мне не ясно, что существует разумный способ написать конструктор копирования для inline_allocator.

В другом потоке StackOverflow Эрик Мельский предоставил эту ссылку классу в Chromium:

http://src.chromium.org/svn/trunk/src/base/stack_container.h

что интересно, но это не замена на замену для std::string, потому что он обертывает std::basic_string в контейнере, так что вам нужно вызвать перегруженный operator->(), чтобы перейти к std::basic_string.

Я не могу найти других решений этой проблемы. Может быть, нет хорошего решения? И если это правда, то понятия std::basic_string и std::allocator плохо испорчены? Я имею в виду, похоже, что это должно быть очень простым и простым вариантом использования для std::basic_string и std::allocator. Я полагаю, что концепция std::allocator разработана в первую очередь для пулов, но я думаю, что она также должна охватывать это.

Кажется, что семантика перемещения rvalue-reference в С++ 0x может сделать запись inline_allocator, если строковая библиотека переписана так, что basic_string использует конструктор перемещения своего распределителя вместо копировать конструктор. Кто-нибудь знает, что перспектива для этого результата?

Моему приложению нужно построить миллион крошечных строк ASCII в секунду, поэтому я написал свой собственный строковый класс с фиксированной длиной, основанный на Boost.Array, который отлично работает, но это все равно беспокоит меня.

4b9b3361

Ответ 1

Андрей Александреску, программист на С++ extraordinaire, который написал "Modern С++ Design", однажды написал замечательную статью о создании различных реализаций строк с настраиваемыми системами хранения. В его статье (приведенной здесь) описывается, как вы можете делать то, что вы описали выше, в качестве особого случая гораздо более общей системы, которая может обрабатывать всевозможные умные распределения памяти требования. Это не так много говорит о std::string и больше фокусируется на полностью настроенном строковом классе, но вам может понадобиться изучить его, поскольку в реализации есть некоторые настоящие камни.

Ответ 2

С++ 2011 действительно поможет вам:)

Дело в том, что концепция allocator в С++ 03 была искалечена. Одно из требований заключалось в том, что распределитель типа A должен иметь возможность освобождать память от любого другого распределителя от типа A... К сожалению, это требование также расходится с генераторами с сохранением состояния, каждый из которых подключен к своему собственному пулу.

Ховард Хиннант (который управляет подгруппой STL коммитов С++ и реализует новый STL с нуля для С++ 0x) исследовал распределители на основе стека на его веб-сайте, от которого вы можете получить вдохновение.

Ответ 3

Это вообще не нужно. Он назывался "оптимизацией коротких строк", и большинство реализаций std::string уже включают его. Это может быть трудно найти, но, как правило, там все равно.

Только, например, вот соответствующий фрагмент sso_string_base.h, который является частью MinGW:

  enum { _S_local_capacity = 15 };

  union
  {
_CharT           _M_local_data[_S_local_capacity + 1];
size_type        _M_allocated_capacity;
  };

Элемент _M_local_data является подходящим для него пространством для хранения (до) 15 символов (плюс терминатор NUL) без выделения места в куче.

Если память используется, библиотека Dinkumware, содержащаяся в VС++, выделяет пространство для 20 символов, хотя прошло некоторое время с тех пор, как я посмотрел, поэтому я не могу поклясться в этом (и отслеживание большинства вещей в их заголовках, как правило, является боль, поэтому я предпочитаю избегать поиска, если смогу).

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

Ответ 4

Я считаю, что код из Chromium просто переносит вещи в приятную оболочку. Но вы можете получить тот же эффект без использования контейнера оболочки Chromium.

Поскольку объект распределителя часто копируется, он должен содержать ссылку или указатель на память. Итак, что вам нужно сделать, это создать буфер хранения, создать объект-распределитель, а затем вызвать конструктор std::string с помощью распределителя.

Это будет намного сложнее, чем использование класса-оболочки, но должно получить тот же эффект.

В моем вопросе о векторах стека вы можете увидеть пример метода verbose (по-прежнему используя хром-материал).