Почему компиляторы не могут оптимизировать цикл для 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 шт):

Автор решения: Pavel Mayorov

Согласно стандарту, char* (который лежит внутри std::string) может указывать на любой объект, в том числе и на std::string. И у компилятора нет никаких свидетельств обратного, потому он и вынужден генерировать код исходя из предположения, что присваивание str[i]=0 может изменить базовый адрес строки.

В то же время, char8_t* не может указывать ни на какой объект кроме char8_t (на момент разыменования), потому для std::u8string таких проблем не наблюдается.

Да, это означает что std::u8string быстрее std::string, а потому предпочтительнее.

→ Ссылка