LINUX.ORG.RU

Передача в функцию тяжёлого temporary

 


0

9

Допустим, у меня есть следующий код:

#include <string>
#include <vector>

void foo(const std::vector<std::string> &vec)
{
    /* произвольные операции с vec */
}

int main(int, char **)
{
    for (unsigned i = 0; i < 1e6; ++i) {
        foo({"foo" /* много букв */,
             "bar" /* много букв */,
             "baz" /* много букв */});
    }
}

Под «много букв» понимаются строки, достаточно длинные для того, чтобы исключить small string optimization.

При выполнении данной программы я наблюдаю (clang 3.9.0, gcc 6.2.1, -std=с++14, наблюдения произведены с помощью valgrind), что вне зависимости от уровня оптимизации происходит 7 * 1e6 выделений памяти.

Отсюда возникает два вопроса:

  1. Почему аллокаций 7 миллионов, а не 4, учитывая move semantics и всё такое?
  2. Почему компилятор не может построить вектор со строками статически в .rodata, учитывая, что он передаётся по константной ссылке и не изменяется? Или какие-то свойства языка запрещают так делать?

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

★★★★★

Последнее исправление: intelfx (всего исправлений: 4)

Ответ на: комментарий от anonymous

Затем, что список типов на практике всегда будет содержать один элемент: std::initializer_list<const char *>.

intelfx ★★★★★
() автор топика
Ответ на: комментарий от intelfx

У тебя const ссылка. Что можно сделать со статическим вектором через неё?

anonymous
()
Ответ на: комментарий от Kuzy

И можно получить куда более страшные баги чем просадку производительности. Я так уже нарвался на умных указателях ;)

invy ★★★★★
()
Ответ на: комментарий от Kuzy

Можно, но бессмысленно.

А если всё это счастье имеет отношение к API, которое ты используешь... Например у меня надо держать указатель на прокси объект соединяющийся через dbus, если указатель вдруг удалится, то ивенты приходить не будут. И вот я случайно передал через move так указатель и потом очень долго не мог понять, почему же я ивенты не получаю, т.к. после предечи умный указатель удалился и всё.

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)

Нет у меня «по месту».

То есть, ты можешь написать

foo(make_static_vector<__LINE__, std::string>({"one", "two", "three"}));
...
foo(make_static_vector<__LINE__, std::string>({"four", "five", "six"}));
Но не можешь
static std::vector<std::string> foo_arg1{"one", "two", "three"};
foo(foo_arg1);
...
static std::vector<std::string> foo_arg2{"four", "five", "six"};
foo(foo_arg2);
? Или я чего-то недопонимаю?

kawaii_neko ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.