Гарантируется ли, что std :: string не вернет память спонтанно?

Гарантируется ли стандартом, что std::string не будет самопроизвольно возвращать выделенную память при переназначении из строки меньшего размера?

Другими словами:

std::string str = "Some quite long string, which needs a lot of memory";
str = "";
str = "A new quite long but smaller string"; // Guaranteed to not result in a heap allocation?

Я спрашиваю, потому что полагаюсь на это, чтобы избежать фрагментации кучи.

если выделение новой строки меньше предыдущего, выделение не происходит. Если для новой строки требуется больше выделения, чем для текущей, происходит перераспределение. Подобно std :: vector.

Samer Tufail 25.09.2018 12:19

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

Fureeish 25.09.2018 12:20

Даже если строка действительно «спонтанно возвращает память», этого недостаточно, чтобы избежать фрагментации кучи. Строка использует распределитель (по умолчанию объект типа std::allocator<char>, но его можно изменить) для выделения и освобождения памяти, а распределитель может снова использовать механизм нижнего уровня (например, варианты операторов new и delete) для фактического выделения и освободить. Если любой этих шагов решит не освобождать память нижнему уровню, это может повлиять на фрагментацию кучи.

Peter 25.09.2018 12:34
Я спрашиваю, потому что полагаюсь на это, чтобы избежать фрагментации кучи. Именно по этой причине я написал свою память контролер для std::string
Peter VARGA 25.09.2018 14:25

Если вам нужно гарантировать такое поведение, вы всегда можете использовать свой собственный распределитель.

doron 25.09.2018 14:26

@AlBundy: что за контроллер памяти?

geza 25.09.2018 15:00

По моему собственному опыту, если мне нужно произнести фразу «Я зависим от предотвращения фрагментации кучи», это очень хорошее время, чтобы начать обдумывать определение точных требований низкого уровня и, возможно, развертывание собственных процедур распределения.

Cort Ammon 25.09.2018 20:06
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
32
7
3 006
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Никаких гарантий.

[string.cons]/36 определяет присвоение const char*std::string в терминах назначения перемещения, определение которого:

[string.cons]/32

basic_string& operator=(basic_string&& str)  noexcept(/*...*/)

Effects: Move assigns as a sequence container, except that iterators, pointers and references may be invalidated.

Это показывает, что Комитет позволил реализации свободно выбирать между операцией по признанию недействительной и более консервативной. И чтобы было понятнее:

[basic.string]/4

References, pointers, and iterators referring to the elements of a basic_­string sequence may be invalidated by the following uses of that basic_­string object:

  • (4.1) as an argument to any standard library function taking a reference to non-const basic_­string as an argument.
  • (4.2) Calling non-const member functions, except operator[], at, data, front, back, begin, rbegin, end, and rend.

I ask because i'm depending on this to avoid heap fragmentation.

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

На практике большинство известных мне реализаций не перераспределяют память в случае вашего вопроса. Это можно проверить путем тестирования и / или проверки документа по реализации и, в конечном итоге, исходного кода.

Вы можете себе представить, насколько нежелательной была бы такая гарантия (если предположить, что она была предоставлена), если бы вы сохранили адрес Геттисберга в строке, а затем заменили бы его на «Hello World».

Cort Ammon 25.09.2018 20:28

Ссылка CPP указывает, что присвоение указателю на символ

Replaces the contents with those of null-terminated character string pointed to by s as if by *this = basic_string(s), which involves a call to Traits::length(s).

Это «как будто» фактически сводится к присвоению rvalue, поэтому следующий сценарий вполне возможен:

  1. Создается новая временная строка.
  2. Строка Этот крадет свое содержимое как через присвоение ссылке rvalue.

cppreference обычно надежен, но приведенный в кавычках оператор подразумевает, что существует гарантированная замена буфера, то есть чушь. В остальном это хорошая концептуальная модель. Но это просто незначительно проще, чем описание стандарта, указанное в ответе YSC, что поэтому было бы предпочтительнее.

Cheers and hth. - Alf 25.09.2018 12:34

@ Cheersandhth.-Альф cppreference перефразирует стандартный [string.cons]

Caleth 25.09.2018 12:39

@ Cheersandhth.-Альф Правда? Он говорит «как если бы», что в Стандарте всегда означает «в отношении наблюдаемых побочных эффектов, за исключением немногих побочных эффектов построений / разрушений».

bipll 25.09.2018 12:46

@rustyx тоже можно. Вы можете представить это как временное похищение существующего распределения с последующим его возвратом.

Caleth 25.09.2018 14:01

@rustyx Стандарт просто говорит об эффекте. Учитывая, что эффект x = "hi"; такой же, как эффект x.assign("hi");, реализация будет эффективна для обоих. libstdC++, например, имеет свой operator=(const CharT*), просто вызывающий assign напрямую.

Barry 25.09.2018 15:40

Если ваши строки короткие (до 15 или 22 байтов, в зависимости от компилятора / std lib) и вы используете относительно недавний компилятор в режиме C++ 11 или более поздней версии, то вы, вероятно, выиграете от Оптимизация коротких строк (SSO) . В этом случае содержимое строки отдельно не выделяется в куче.

Эта ссылка также содержит много подробностей об общих реализациях и стратегиях распределения.

Однако обе строки в вашем примере слишком длинные для SSO.

Гарантировано ли это стандартом? Гарантируется ли SSO стандартом?

pipe 26.09.2018 02:40

@pipe Нет, это не то, что Пол имел в виду в: "вы вероятно, чтобы воспользоваться оптимизацией коротких строк (SSO)".

YSC 26.09.2018 09:17

@YSC Хорошо, но вопрос довольно конкретный, и OP уже знает, что это может произойти, так как он зависит от него, поэтому я не понимаю, на что это на самом деле отвечает.

pipe 26.09.2018 10:27

@pipe Я согласен, что этот ответ немного неверен, но на него ответили сразу после того, как OP задал свой вопрос. В то время вопрос не был помечен как языковед, и после этого он будет отредактирован. Это ответ на часть проблемы OP (mem frag) и дает интересную информацию. Я проголосовал за то, что он стоит.

YSC 26.09.2018 11:44

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

Paul Floyd 26.09.2018 12:52

Is it guaranteed by the standard that std::string will not give back allocated memory spontaneously if reassigned from a string of a smaller size?

Независимо от фактического ответа (т.е. «Нет, без гарантии») вы должны руководствоваться следующим принципом: Если не очевидно, что это так, не думайте, что это так.

В вашем конкретном случае - если вам нужен жесткий контроль над поведением кучи, вы можете вообще не использовать std::string (возможно, это зависит от обстоятельств). И вы можете не захотеть использовать распределитель по умолчанию (опять же, возможно); и вы можете захотеть запоминать строки; и т. д. Что вам обязательно нужно сделать, так это делать меньше предположений, измерять, если возможно, и иметь четкий дизайн, гарантирующий, что ваши потребности будут удовлетворены.

Другие вопросы по теме