Как мне выделить std::string в стеке, используя реализацию glibc string?
Вопрос
int main(void)
{
std::string foo("foo");
}
Насколько я понимаю, приведенный выше код использует распределитель по умолчанию для вызова new .Таким образом, даже несмотря на то, что std::string foo выделен в стеке, внутренний буфер внутри foo выделен в куче.
Как я могу создать строку, которая полностью размещается в стеке?
Решение
Недавно я сам хотел сделать именно это и обнаружил, что следующий код освещает:
Это определяет новый std::allocator
который может обеспечить распределение на основе стека для первоначального выделения хранилища для контейнеров STL.В итоге я нашел другой способ решить свою конкретную проблему, поэтому на самом деле я сам не использовал код, но, возможно, он будет полезен вам.Обязательно прочитайте комментарии в коде, касающиеся использования и предостережений.
Для тех, кто сомневался в полезности и разумности этого, рассмотрим:
- Часто вы априори знаете, что ваша строка имеет разумный максимальный размер.Например, если строка будет хранить 32-разрядное целое число в десятичном формате, вы знаете, что для этого вам не нужно более 11 символов.В этом случае нет необходимости в строке, которая может динамически увеличиваться до неограниченного размера.
- Выделение из стека во многих случаях происходит быстрее, чем выделение из кучи.
- Если строка создается и уничтожается часто (предположим, что это локальная переменная в часто используемой служебной функции), выделение из стека вместо кучи позволит избежать оттока в распределителе кучи, вызывающего фрагментацию.Для приложений, которые используют много памяти, это может изменить правила игры.
Некоторые люди прокомментировали, что строка, использующая выделение на основе стека, не будет std::string
как будто это каким-то образом уменьшает его полезность.Правда, вы не можете использовать эти два понятия взаимозаменяемо, поэтому вы не сможете передать свой stackstring
к функциям, ожидающим std::string
.Но (если вы сделаете это правильно), вы сможете использовать все те же функции-члены на вашем stackstring
которые вы используете сейчас на std::string
, как find_first_of()
, append()
, и т.д. begin()
и end()
будет по-прежнему работать нормально, так что вы сможете использовать многие алгоритмы STL.Конечно, этого не будет std::string
в самом строгом смысле, но это все равно будет "строка" в практическом смысле, и она все равно будет весьма полезна.
Другие советы
Проблема в том, что std::basic_string
имеет параметр шаблона для распределителя.Но std::string
не является шаблоном и не имеет параметров.
Таким образом, вы могли бы в принципе использовать экземпляр std::basic_string
с распределителем, который использует память в стеке, но это не было бы std::string
.В частности, вы не получили бы полиморфизма во время выполнения, и вы не смогли бы передать результирующие объекты в функции, ожидающие std::string
.
Ты не можешь.За исключением...
std::string
является экземпляром
std::basic_string<class CharType,
class Traits=char_traits<CharType>,
class Allocator=allocator<CharType> >
Предположительно, вы могли бы определить класс распределителя, который использует распределять для управления памятью.Это сработало бы только в том случае, если сам Распределитель и basic_string
методы, которые вызывают его прямо или косвенно, - это все inline
.A basic_string
объект, созданный с помощью этого распределителя, не будет быть a std::string
, но он будет вести себя (в основном) подобным образом.Однако это было бы изрядным объемом работы при ограниченной прибыли.В частности, использование этого класса для возврата значений из функции было бы шагом, ограничивающим карьеру.
Я понятия не имею почему вы или кто-то другой захотел бы это сделать.
Я подозреваю, что сделать такую вещь было бы трудно, интересно, почему вы хотите это сделать?Чтобы выделить что-то полностью в стеке, компилятор должен знать во время компиляции, каков точный размер объекта - в вашем примере ему нужно было бы знать не только размер std::string
метаданные, но также и размер самих строковых данных.Это не слишком гибко, вам, вероятно, понадобятся разные типы строк в зависимости от размера строковых данных, которые вы хотите в них включить - не то чтобы это было невозможно сделать, просто это немного усложнило бы ситуацию.
- std::string всегда будет управлять своим внутренним хранилищем с помощью new / delete .
- Не уверен, почему ваш вопрос содержит реализация строки glibc.Строковая реализация стандартной библиотеки c ++ не имеет ничего общего с glibc ( глибц ).
- Единственный способ сохранить строку в стеке - это использовать массив символов C в стеке (подобно тому, что описал Shhnap).Но это, вероятно, все равно не то, чего вы хотите :-)