std :: string без свободного выделения памяти хранилища - PullRequest
33 голосов
/ 31 марта 2011

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

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

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

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

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

Iпопытался написать класс 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 в C ++ 0x может позволить написатьinline_allocator, если библиотека строк переписана так, что basic_string использует конструктор перемещения своего распределителя вместо конструктора копирования.Кто-нибудь знает, каковы перспективы этого результата?

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

Ответы [ 4 ]

16 голосов
/ 31 марта 2011

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

10 голосов
/ 31 марта 2011

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

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

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

6 голосов
/ 31 марта 2011

Это обычно не нужно.Это называется «оптимизация короткой строки», и большинство реализаций 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, включенная в VC ++, выделяет пространство для20 символов, хотя с тех пор, как я посмотрел, прошло довольно много времени, поэтому я не могу поклясться в этом (и отследить большую часть чего-либо в их заголовках обычно бывает больно, поэтому я предпочитаю избегать поиска, если смогу).

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

2 голосов
/ 31 марта 2011

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

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

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

Вы можете увидеть пример многословного метода (все еще использующего хром), в моем вопросе о векторах стека .

...