提问人:Patrick 提问时间:6/4/2018 更新时间:7/9/2019 访问量:1911
为什么要按值传递string_view?为什么 Visual Studio 不能对此进行优化?
Why pass string_view by value? And why can't Visual Studio optimize this?
问:
根据我的直觉,我假设新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 添加到调用中,如下所示:
auto thisMethodByValueAndMove(int value, std::string_view input) -> void
{
otherMethodByValue(std::move(input));
}
但这似乎无济于事。
Visual Studio 2017 编译器无法对此进行优化是否有原因? 其他编译器是否优化了此模式?
答:
0赞
NN_
7/9/2019
#1
X64 调用约定不允许在不同的寄存器之间传播参数。 编译器可以通过 rcx 和 rdx 传递string_view,但 ABI 反对这一点。https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019
评论
0赞
Patrick
7/10/2019
我知道,但这不是重点。如果通过引用传递string_view,则会在寄存器中传递指向string_view的指针,如果随后将其转发给另一个方法,则仅转发指针。如果传递 string_view by 值,则会在堆栈上复制该值,并且还会在寄存器中传递指向堆栈上此值的指针。如果您随后转发它,它似乎会完整地复制string_view,而不是像通过引用传递时那样只是复制指针。Clang 似乎很好地优化了这一点,而 MSVC 则没有。
0赞
NN_
7/10/2019
没错。另一方面,它可以进行其他优化。例如,值传递的两个string_view对象始终是不同的对象,而两个引用可能指向同一个对象。
评论
mv
string_view
string_view
thisMethodByReference
otherMethodByValue
Do other compilers optimize this pattern?
- 我猜在 Godbolt 测试。MSVC在这里显然太“挑战”了,让他们知道。