Почему компиляторы не могут оптимизировать цикл для std::string?
Почему gcc и clang оптимизируют цикл в memset для std::u8string, но не для std::string? Неужели они считают, что по char& можно изменить N? Значит ли это, что с точки зрения производительности UTF-8 строки лучше хранить в std::u8string, а не в std::string?
Diff для gcc и clang в Compiler Explorer.
Код для std::string:
#include <string>
void chop(int N, std::string str) {
for (int i = 0; i != N; ++i) {
str[i] = 0;
}
}
Ассемблер gcc для std::string:
test edi, edi
jle .L1
movsx rdi, edi
xor eax, eax
.L3:
mov rdx, QWORD PTR [rsi]
mov BYTE PTR [rdx+rax], 0
add rax, 1
cmp rdi, rax
jne .L3
.L1:
ret
Код для std::u8string:
#include <string>
void chop(int N, std::u8string str) {
for (int i = 0; i != N; ++i) {
str[i] = 0;
}
}
Ассемблер gcc для std::u8string:
test edi, edi
jle .L1
mov edx, edi
mov rdi, QWORD PTR [rsi]
xor esi, esi
jmp memset
Ответы (1 шт):
Согласно стандарту, char* (который лежит внутри std::string) может указывать на любой объект, в том числе и на std::string. И у компилятора нет никаких свидетельств обратного, потому он и вынужден генерировать код исходя из предположения, что присваивание str[i]=0 может изменить базовый адрес строки.
В то же время, char8_t* не может указывать ни на какой объект кроме char8_t (на момент разыменования), потому для std::u8string таких проблем не наблюдается.
Да, это означает что std::u8string быстрее std::string, а потому предпочтительнее.