Theoretically, as string_view
is non-owning, it can already be considered a reference. So using by using a reference to a string_view
, you get a reference to a reference.
But it actually seems to depend on the level of optimization you set the compiler to.
Consider the following code:
#include <iostream>
#include <string_view>
void foo(std::string_view str) {
std::cout << str;
}
void bar(std::string_view const &str){
std::cout << str;
}
int main() {
foo("test1");
bar("test2");
}
foo
should be more efficient than bar
, right?
If you compile with gcc 10.1 without optimizations, you get the following assembly for foo
and bar
:
foo(std::basic_string_view<char, std::char_traits<char> >):
push rbp
mov rbp, rsp
sub rsp, 16
mov rax, rdi
mov rcx, rsi
mov rdx, rcx
mov QWORD PTR [rbp-16], rax
mov QWORD PTR [rbp-8], rdx
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-8]
mov rsi, rdx
mov rdx, rax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >)
nop
leave
ret
bar(std::basic_string_view<char, std::char_traits<char> > const&):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov rdx, QWORD PTR [rax]
mov rax, QWORD PTR [rax+8]
mov rsi, rdx
mov rdx, rax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >)
nop
leave
ret
You can see that foo
has more operations than bar
. Seems less efficient.
However, if you set the compiler optimization to -O1
, you get the following assembly
foo(std::basic_string_view<char, std::char_traits<char> >):
sub rsp, 8
mov rdx, rdi
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
add rsp, 8
ret
bar(std::basic_string_view<char, std::char_traits<char> > const&):
sub rsp, 8
mov rsi, QWORD PTR [rdi+8]
mov rdx, QWORD PTR [rdi]
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
add rsp, 8
ret
Now foo
requires one less operation.