Гарантируется ли std :: string не возвращать память спонтанно? - PullRequest
0 голосов
/ 25 сентября 2018

Гарантируется ли стандартом, что 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?

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

Ответы [ 4 ]

0 голосов
/ 26 сентября 2018

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

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

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

0 голосов
/ 25 сентября 2018

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

Заменяет содержимое на строку символов с нулевым символом в конце, на которую указывает s, как будто на * this= basic_string (s), который включает в себя вызов Traits :: length (s).

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

  1. Создана свежая временная строка.
  2. Эта строка крадет ее содержимое, как посредством присвоения rvalue ссылки.
0 голосов
/ 25 сентября 2018

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

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

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

0 голосов
/ 25 сентября 2018

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

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

[string.cons]/32

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

Эффекты : перемещение назначает как контейнер последовательности, за исключением того, что итераторы, указатели и ссылки могут быть недействительными.

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

[basic.string]/4

Ссылки, указатели и итераторы, ссылающиеся на элементы последовательности basic_­string, могут быть признаны недействительнымиследующим использованием этого объекта basic_string:

  • (4.1) в качестве аргумента любой стандартной библиотечной функции, принимающей ссылку на неконстантный basic_­string в качестве аргумента.
  • (4.2) Вызов неконстантных функций-членов, кроме operator[], at, data, front, back, begin, rbegin, end и rend.

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

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

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

...