Как мне выделить std :: string в стеке, используя реализацию строки glibc? - PullRequest
17 голосов
/ 24 апреля 2009
int main(void)
{
   std::string foo("foo");
}

Насколько я понимаю, приведенный выше код использует распределитель по умолчанию для вызова new. Таким образом, хотя std :: string foo размещается в стеке, внутренний буфер внутри foo размещается в куче.

Как мне создать строку, целиком расположенную в стеке?

Ответы [ 5 ]

21 голосов
/ 24 апреля 2009

Недавно я хотел сделать это сам и обнаружил следующий код:

Chronium's stack_container.h

Он определяет новый std::allocator, который может обеспечить выделение на основе стека для начального выделения памяти для контейнеров STL. Я нашел другой способ решения своей конкретной проблемы, поэтому я сам не использовал код, но, возможно, он будет вам полезен. Обязательно прочтите комментарии в коде, касающиеся использования и предостережений.

Тем, кто усомнился в целесообразности и здравомыслии, подумайте:

  • Часто вы априори знаете, что ваша строка имеет разумный максимальный размер. Например, если в строке будет храниться 32-разрядное целое число в десятичном формате, вы знаете, что для этого нужно не более 11 символов. В этом случае не требуется строка, которая может динамически увеличиваться до неограниченного размера.
  • Во многих случаях выделение из стека происходит быстрее, чем выделение из кучи.
  • Если строка часто создается и уничтожается (предположим, это локальная переменная в часто используемой служебной функции), выделение из стека вместо кучи позволит избежать оттока фрагментов в распределителе кучи. Для приложений, которые используют много памяти, это может изменить правила игры.

Некоторые люди отмечают, что строка, использующая распределение на основе стека, не будет std::string, как будто это каким-то образом уменьшает ее полезность. Правда, вы не можете использовать их взаимозаменяемо, поэтому вы не сможете передать свои stackstring функциям, ожидающим std::string. Но (если вы все сделаете правильно), вы сможете использовать все те же функции-члены на stackstring, которые вы используете сейчас на std::string, например find_first_of(), append() и т. Д. begin() и end() все равно будет работать нормально, поэтому вы сможете использовать многие алгоритмы STL. Конечно, это не будет std::string в самом строгом смысле этого слова, но в практическом смысле оно все равно будет «строкой», и все равно будет весьма полезным.

11 голосов
/ 24 апреля 2009

Проблема в том, что std::basic_string имеет параметр шаблона для распределителя. Но std::string не является шаблоном и не имеет параметров.

Таким образом, вы можете в принципе использовать экземпляр std::basic_string с распределителем, который использует память в стеке, но это не будет std::string. В частности, вы не получите полиморфизм во время выполнения и не сможете передать полученные объекты в функции, ожидающие std::string.

4 голосов
/ 24 апреля 2009

Вы не можете. За исключением ...

std::string является экземпляром

std::basic_string<class CharType, 
                  class Traits=char_traits<CharType>, 
                  class Allocator=allocator<CharType> >

Можно было бы определить класс Allocator, который использует alloca для управления памятью. Это будет работать только в том случае, если сам Allocator и методы basic_string, вызывающие его прямо или косвенно, все являются inline. Объект basic_string, созданный с помощью этого распределителя, не будет быть a std::string, но будет вести себя (в основном) так, как он. Тем не менее, это будет изрядное количество работы за ограниченную прибыль. В частности, использование этого класса для возврата значений из функции было бы ограничением карьеры.

Понятия не имею почему вы или кто-либо еще захотите сделать это.

0 голосов
/ 24 апреля 2009
  • std :: string всегда будет управлять своим внутренним хранилищем с помощью new / delete.
  • Не уверен, почему ваш вопрос содержит строковую реализацию glibc . Строковая реализация стандартной библиотеки c ++ не имеет ничего общего с glibc .
  • Единственный способ сохранить строку в стеке - это использовать массив C char в стеке (как описал Shhnap). Но это, вероятно, не то, что вы хотите в любом случае: -)
0 голосов
/ 24 апреля 2009

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

...