Используя мои интуитивные ощущения, я предполагал, что новый string_view необходимо передать по ссылке, поскольку это более эффективно (только указатель передачи вместо полного класса).Однако некоторые источники указывают, что лучше передавать его по значению, избегая проблемы с псевдонимами.
Испытывая несколько альтернатив, я подтвердил свое интуитивное чувство, что передача по ссылке была быстрее, если функция не делала ничего, кроме пересылки string_view (все источники, скомпилированные с /Ox
)
Например, этот код
extern auto otherMethodByReference(const std::string_view &input) -> void;
auto thisMethodByReference(int value, const std::string_view &input) -> void
{
otherMethodByReference(input);
}
Приведен в этой сборке
00000 48 8b ca mov rcx, rdx
00003 e9 00 00 00 00 jmp ?otherMethodByReference@@YAXAEBV?$basic_string_view@DU?$char_traits@D@std@@@std@@@Z ; otherMethodByReference
При этом код
extern auto otherMethodByValue(std::string_view input) -> void;
auto thisMethodByValue(int value, std::string_view input) -> void
{
otherMethodByValue(input);
}
Приведен вэта сборка
00000 48 83 ec 38 sub rsp, 56 ; 00000038H
00004 0f 10 02 movups xmm0, XMMWORD PTR [rdx]
00007 48 8d 4c 24 20 lea rcx, QWORD PTR $T1[rsp]
0000c 0f 29 44 24 20 movaps XMMWORD PTR $T1[rsp], xmm0
00011 e8 00 00 00 00 call ?otherMethodByValue@@YAXV?$basic_string_view@DU?$char_traits@D@std@@@std@@@Z ; otherMethodByValue
00016 48 83 c4 38 add rsp, 56 ; 00000038H
0001a c3 ret 0
Ясно, что вы можете видеть, что копия string_view создается в стеке и затем передается другому методу.
Однако мне было интересно, почему некомпилятор оптимизирует это и просто передает аргумент string_view непосредственно другому методу.В конце концов, в Windows x64 ABI передача значения класса больше, чем умещается в регистре, всегда выполняется путем копирования регистра в стек и передачи указателя на него в правильном регистре.В этом примере кода я ожидаю, что компилятор просто перенаправит указатель на следующую функцию, как в случае передачи по ссылке.В конце концов, компилятор может видеть, что значение аргумента впоследствии не используется, поэтому вместо создания копии он может просто переслать адрес.
Я попытался добавить к вызову std :: move, напримерthis:
auto thisMethodByValueAndMove(int value, std::string_view input) -> void
{
otherMethodByValue(std::move(input));
}
Но это, похоже, не помогает.
Есть ли причина, по которой компилятор Visual Studio 2017 не может оптимизировать это?Оптимизируют ли другие компиляторы этот шаблон?