Где-то в моем мозгу шепчет голос:

В C ++ массиву не нужно больше памяти, чем нужно количеству элементов.

std::string str = "aabbcc"; 
std::array<std::string, 3> str_array = {"aa", "bb", "cc"}; 

Соответственно, оба должны иметь одинаковый размер, поскольку (в отличие от Java) отдельное поле size или подобное не существует. Но я не нашел ссылку.

Это правда? При каких обстоятельствах это не так?

0
Michael Dorner 28 Фев 2018 в 01:21

5 ответов

Лучший ответ

В C ++ массиву не нужно больше памяти, чем нужно количеству элементов.

Это правда. Необработанный массив имеет размер, равный размеру его элемента, умноженному на количество элементов. Так

int array[10];

Имеет размер sizeof(int) * std::size(array). std::array такой же, но разрешено иметь отступ

std::array<int, 10> array;

Имеет размер sizeof(int) * std::size(array) + P, где P - некоторое целое число отступов.

Ваш пример не совсем то же самое. std::string является контейнером. Он имеет свой собственный размер, который отделен от того, что он содержит. Так что sizeof(std::string) всегда будет одним и тем же, независимо от того, сколько символов в строке. Так что игнорируя оптимизацию коротких строк

std::string str = "aabbcc"; 

Занимает sizeof(std::string) плюс сколько угодно строки, выделенной для базовой c-строки. Это не то же значение, что

std::array<std::string, 3> str_array = {"aa", "bb", "cc"};

Так как теперь у вас есть 3 * sizeof(std::string) плюс все, что выделено для каждой строки.

2
NathanOliver 28 Фев 2018 в 13:48

Хранить строки на любом языке сложнее, чем вы думаете. C ++ std::string должен предоставить вам непрерывное хранилище для содержимого. Кроме того, std::string может содержать больше вещей, таких как указатель / итератор до последнего символа, количество символов в нем и т. Д. std::string::size должен быть равен O (1), поэтому он должен хранить больше информация, чем просто буфер. Кроме того, большинство реализаций стандартной библиотеки предоставляют SSO (оптимизация небольших строк). Когда SSO включен, std::string выделяет небольшой буфер, чтобы избежать ненужных динамических распределений. Вы также можете зарезервировать больше памяти, чем вам нужно. Допустим, вам нужно собрать 800-1000 символов в цикле. Вы можете сделать это так:

std::string str;
for(...)
    str += some_character;

Но это вызовет ненужные выделения памяти и освобождения. Если вы можете оценить количество символов, которое хотите сохранить, вам следует {{X0} } память.

std::string str;
str.reserve(1000);
for(...)
    str.push_back(some_character);

Затем вы всегда можете shrink_to_fit сэкономить память :

str.shrink_to_fit();

Есть и другие вещи, о которых вы должны знать:

  • reserve увеличивает емкость, но size остается прежним. Это означает, что std::string также должен хранить (или иметь возможность вычислять), сколько еще позволяет вместимость буфера символов.
  • строковые литералы заканчиваются нулем
  • std::basic_string::c_str должен возвращать массив символов с нулевым символом в конце, поэтому возможно, что std::string также содержит нулевой терминатор (к сожалению, я не уверен, как это сделать)
  • есть больше кодировок и наборов символов - ASCII - только один из них. В кодированных строках UTF-8 и UTF-16 может потребоваться использовать несколько сохраненных элементов, чтобы сложить одну кодовую точку, но это сложнее.
4
Poeta Kodu 27 Фев 2018 в 22:46

Практически каждая строка может содержать следующую информацию:

  • Размер строки, то есть количество символов в ней.

  • Емкость памяти, удерживающей символы строки.

  • Значение строки.

Кроме того, он также может содержать:

  • Копия его распределителя и счетчик ссылок для значения.
1
Archie Yalakki 27 Фев 2018 в 22:35

Они не имеют одинаковый размер. Строки сохраняются с нулевым символом в конце, давая вам дополнительный байт для каждой строки.

-3
Demosthenes 27 Фев 2018 в 22:25

Соответственно, оба должны иметь одинаковый размер (например, 6 байтов),

Не правильный вывод.

Память, используемая std::string, если вы хотите назвать ее размер, состоит как минимум из указателя и памяти, выделенной для хранения данных.

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

Данный

std::string s = "aabbcc";
std::string a = "aa";
std::string b = "bb";
std::string c = "cc";

mem(s) != mem(a) + mem(b) + mem(c)
1
R Sahu 27 Фев 2018 в 22:30