std::string_view
chegou ao C ++ 17 e é amplamente recomendado usá-lo em vez de const std::string&
.
Uma das razões é o desempenho.
Alguém pode explicar como exatamente std::string_view
será / será mais rápido do que const std::string&
quando usado como um tipo de parâmetro? (vamos supor que não sejam feitas cópias no chamado)
c++
string
c++17
string-view
Patryk
fonte
fonte
std::string_view
é apenas uma abstração do par (char * begin, char * end). Você o usa ao fazer umastd::string
cópia desnecessária.std::string
(string_view pode aceitar matrizes brutas, vetores,std::basic_string<>
com alocadores não padrão etc. etc. etc. etc. Ah, e outras string_views obviamente)Respostas:
std::string_view
é mais rápido em alguns casos.Primeiro,
std::string const&
exige que os dados estejam em umastd::string
matriz C bruta, e não em uma bruta C,char const*
retornada por uma API C,std::vector<char>
produzida por algum mecanismo de desserialização etc. A conversão de formato evitada evita a cópia de bytes e (se a cadeia for maior que a SBO¹ para astd::string
implementação específica ) evita uma alocação de memória.Nenhuma alocação é feita no
string_view
caso, mas haveria se fosse utilizadofoo
um emstd::string const&
vez de umstring_view
.A segunda razão realmente grande é que ela permite trabalhar com substrings sem uma cópia. Suponha que você esteja analisando uma string json de 2 gigabytes (!) ². Se você analisá-lo
std::string
, cada nó de análise em que eles armazenam o nome ou o valor de um nó copia os dados originais da sequência de 2 gb para um nó local.Em vez disso, se você analisá-lo como
std::string_view
s, os nós se referem aos dados originais. Isso pode economizar milhões de alocações e reduzir pela metade os requisitos de memória durante a análise.A aceleração que você pode obter é simplesmente ridícula.
Este é um caso extremo, mas outros casos "obtenha uma substring e trabalhe com ele" também podem gerar acelerações decentes com
string_view
.Uma parte importante da decisão é o que você perde usando
std::string_view
. Não é muito, mas é alguma coisa.Você perde rescisão nula implícita, e é isso. Portanto, se a mesma cadeia de caracteres for passada para 3 funções, todas as quais requerem um terminador nulo, a conversão para
std::string
uma vez pode ser sensata. Portanto, se seu código precisar de um terminador nulo e você não espera que as sequências sejam alimentadas por buffers de origem C ou similares, talvez faça umstd::string const&
. Caso contrário, faça umastd::string_view
.Se
std::string_view
houvesse uma bandeira que declarasse que era nula encerrada (ou algo mais sofisticado), removeria até o último motivo para usar umstd::string const&
.Há um caso em que tirar um
std::string
semconst&
é ideal sobre umstd::string_view
. Se você precisar possuir uma cópia da sequência indefinidamente após a chamada, aceitar valores será eficiente. Você estará no caso do SBO (e não haverá alocações, apenas algumas cópias de caracteres para duplicá-lo) ou poderá mover o buffer alocado pelo heap para um localstd::string
. Com duas sobrecargasstd::string&&
estd::string_view
pode ser mais rápido, mas apenas marginalmente, e causaria um inchaço modesto no código (o que poderia custar todos os ganhos de velocidade).¹ Otimização de buffer pequeno
² Caso de uso real.
fonte
Uma maneira de o string_view melhorar o desempenho é permitir a remoção de prefixos e sufixos facilmente. Sob o capô, string_view pode apenas adicionar o tamanho do prefixo a um ponteiro em algum buffer de string ou subtrair o tamanho do sufixo do contador de bytes, isso geralmente é rápido. Por outro lado, std :: string precisa copiar seus bytes quando você faz algo como substr (dessa forma, você obtém uma nova string que possui seu buffer, mas em muitos casos você deseja apenas obter parte da string original sem copiar). Exemplo:
Com std :: string_view:
Atualizar:
Eu escrevi uma referência muito simples para adicionar alguns números reais. Eu usei uma incrível biblioteca de benchmark do Google . As funções comparadas são:
Resultados
(x86_64 linux, gcc 6.2, "
-O3 -DNDEBUG
"):fonte
Existem 2 razões principais:
string_view
é uma fatia em um buffer existente, não requer alocação de memóriastring_view
é passado por valor, não por referênciaAs vantagens de ter uma fatia são múltiplas:
char const*
ouchar[]
sem alocar um novo bufferDesempenho melhor e mais consistente por todo o lado.
A passagem por valor também tem vantagens sobre a passagem por referência, porque é um alias.
Especificamente, quando você tem um
std::string const&
parâmetro, não há garantia de que a cadeia de referência não seja modificada. Como resultado, o compilador deve buscar novamente o conteúdo da sequência após cada chamada em um método opaco (ponteiro para dados, comprimento, ...).Por outro lado, ao passar um
string_view
valor por, o compilador pode determinar estaticamente que nenhum outro código pode modificar o comprimento e os ponteiros de dados agora na pilha (ou nos registradores). Como resultado, ele pode "armazená-las" em cache em chamadas de função.fonte
Uma coisa que ele pode fazer é evitar a construção de um
std::string
objeto no caso de uma conversão implícita a partir de uma sequência terminada nula:fonte
const std::string str{"goodbye!"}; foo(str);
, provavelmente, não vai ser qualquer mais rápido com string_view do que com corda &string_view
será lento, pois ele tem que copiar dois ponteiros em vez de um ponteiroconst string&
?std::string_view
é basicamente apenas um invólucro em torno de umconst char*
. E passarconst char*
significa que haverá um ponteiro a menos no sistema em comparação com passarconst string*
(ouconst string&
), porquestring*
implica algo como:Claramente, com a finalidade de transmitir argumentos const, o primeiro ponteiro é supérfluo.
ps Uma diferença substancial entre
std::string_view
econst char*
, no entanto, é que as string_views não precisam ter terminação nula (elas têm tamanho interno), e isso permite a emenda aleatória no local de seqüências mais longas.fonte
std::string_view
s são apenasconst char*
s chiques , ponto final. O GCC os implementa assim:class basic_string_view {const _CharT* _M_str; size_t _M_len;}
std::string const*
. E esse diagrama é ininteligível. @ n.caillou: Seu próprio comentário já é mais preciso que a resposta. Isso fazstring_view
mais do que "chiquechar const*
" - é realmente bastante óbvio.std::string const*
estd::string const&
é o mesmo, não é?