Почему gcc не использует memmove в std :: uninitialized_copy?
std::uninitialized_copy
копирует в неинициализированный диапазон памяти. Это можно сделать с помощьюmemmove
для побитовых копируемых типов. Я прошел через пример кода в GDB (компиляция с GCC 5.2.0). Тем самым я заметил, чтоmemmove
не используется вообще.
В примере__is_trivial(Bar)
используется для определенияmemmove
может быть использовано. (Правильно) оцениваетfalse
какBar
имеет нетривиальный конструктор по умолчанию (см. вызовstd::__uninitialized_copy<false>::__uninit_copy(...)
вbits/stl_uninitialized.h
линия123
и далее). Но почему__is_trivial
даже имеет отношение кstd::uninitialized_copy
? В соответствии сБьярне std::is_trivially_copyable
должно быть достаточно. Обратите внимание, что последний оцениваетtrue
в примере, т.е.memmove
оптимизацияприменимо.
Я знаю, что стандарт не требует какой-либо конкретной реализацииstd::uninitialized_copy
, Мне просто интересно, почему__is_trivial
является предпочтительным, даже еслиstd::is_trivially_copyable
присутствует как применимая альтернатива реализации gcc?
Пример кода:
#include <iostream>
#include <memory>
#include <vector>
#include <type_traits>
struct Bar
{
Bar () : v(42) {};
Bar(Bar const &) = default;
Bar(Bar &&) = default;
Bar & operator=(Bar &&) = default;
Bar & operator=(Bar const &) = default;
~Bar() = default;
int v;
};
int main() {
std::cout
<< std::is_trivially_move_constructible<Bar>::value
<< " " << std::is_trivially_copy_constructible<Bar>::value
<< " " << std::is_trivially_copyable<Bar>::value
<< " " << std::is_trivial<Bar>::value
<< " " << __is_trivial(Bar) << std::endl;
size_t const num_elements = 1 << 27;
std::vector<Bar> v(num_elements);
Bar * vc = (Bar *) std::malloc(num_elements * sizeof(Bar));
std::uninitialized_copy(v.begin(), v.end(), vc);
std::free(vc);
}
Пример вывода:1 1 1 0 0
Обновить: Мы провели несколько тестов, сравнивая фактическое время выполненияmemmove
, uninitialized_copy
и простойfor
петля. ЕслиBar
тривиально (ср.__is_trivial(Bar)
),uninitialized_copy
так быстро, какmemmove
если нет,uninitialized_copy
так же быстро, как нашfor
петля. В общем и целомmemmove
был только значительно быстрее (2x
) на маленькомBar
с (т.е. изменитьint v;
вchar v;
). В остальном производительность была практически одинаковой.
редактировать: Правильные ссылки наstd::is_trivially_...
, Точное название государства.