Using my gut feeling I assumed by the new string_view needed to be passed by reference, since this is more efficient (only pass pointer instead of a full class). However, several sources indicate that it's better to pass it by value, avoiding the 'aliasing' problem.
When trying out several alternatives, I confirmed my gut feeling that passing by reference was faster, if the function did nothing more than just forwarding the string_view (all sources compiled with /Ox
)
For example, this code
extern auto otherMethodByReference(const std::string_view &input) -> void;
auto thisMethodByReference(int value, const std::string_view &input) -> void
{
otherMethodByReference(input);
}
Resulted in this assembly
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
While this code
extern auto otherMethodByValue(std::string_view input) -> void;
auto thisMethodByValue(int value, std::string_view input) -> void
{
otherMethodByValue(input);
}
Resulted in this assembly
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
Clearly you can see that a copy of the string_view is made on the stack and then passed to the other method.
However, I was wondering, why doesn't the compiler optimize this and simply pass the string_view argument directly to the other method. After all, in the Windows x64 ABI a pass-by-value of a class larger than what fits in a register is always done by copying the register on the stack, and passing a pointer to it in the correct register. I would expect in this example code that the compiler would simply forward the pointer to the next function, just like in the pass-by-reference case. After all, the compiler can see that the value of the argument is not used afterwards, so instead of making a copy, it can just forward the address.
I tried adding std::move to the call, like this:
auto thisMethodByValueAndMove(int value, std::string_view input) -> void
{
otherMethodByValue(std::move(input));
}
But that doesn't seem to help.
Is there a reason why the Visual Studio 2017 compiler cannot optimize this? Do other compilers optimize this pattern?