Ответ на квиз
#новичкам
Напомню код:
std::string makeText()
{
std::string s = "Hello World!";
return s;
}
int main()
{
std::string t = makeText();
std::cout << t << endl;
}
В С++ все по классике зависит от кучи деталей. Но в первую очередь от версии стандарта и компилятора. Поэтому в теории, ответом могут быть и 0, и 1, и 3. Но давайте сузим спектр обсуждений до С++23 и gcc.
Во времена, когда я только начинал изучать C++, мой ответ был бы «3»: один раз для начального выделения памяти под строку
s, затем ещё два — для возврата по значению: сначала копирование-инициализация временного объекта из
s, затем копирование-инициализация
t из временного объекта. Каждое копирование должно триггерить аллокацию нового буфера.
Потом я узнал об оптимизации copy elision(с С++17 есть в стандарте) и конкретно
NRVO и понял, что при возврате по значению умный компилятор скорее всего избежит создания трёх объектов, и сразу создаст объект с нужной строкой в main. После этого мой ответ был бы уже 1.
Но это ещё не всё. От
std::string не требуется выделять память в куче (или любую другую память, о которой знает его аллокатор). Требуется лишь, чтобы он мог тем или иным способом хранить строку символов произвольной длины. Действительно, в общем случае это подразумевает выделение памяти в какой-то момент. Но наш случай не общий вообще-то. Текст
"Hello World!" довольно короткий. Это 12 символов; 13, если считать завершающий нулевой символ. Типичная реализация
std::string требует трёх указателей для полноценного функционирования (примерно также как мы рассказали
тут для std::vector). Если на 64-разрядной машине размер указателя равен 8 символам, то наш текст занимает меньше, чем два указателя. Текст достаточно мал, чтобы поместиться внутрь объекта, память для которого выделена на стеке. Это идеальный кандидат для
оптимизации малого буфера (small buffer optimization, SBO).
Подробнее про эту оптимизацию и как она реализована мы поговорим в следующих постах. Сейчас просто скажу, что
эта оптимизация действительно позволяет аллоцировать небольшие строки внутри объекта не прибегая к динамическим аллокациям.
Вообще говоря, даже если не будут работать оптимизации copy elision, аллокаций все равно не будет, потому что для копирование маленькой строки нужно всего лишь данные со стека скопировать.
Получается, что в коде выше вообще нет аллокаций. Вот
пруф. И это даже без указания флажков оптимизации. И это прекрасно!
Run faster. Stay cool.
#memory #optimization
Обсуждение 16
Обсуждение не доступно в веб-версии. Чтобы написать комментарий, перейдите в приложение Telegram.
Обсудить в Telegram