Estou usando uma biblioteca interna que foi projetada para imitar uma biblioteca C ++ proposta e, em algum momento nos últimos anos, vejo sua interface alterada de usar std::string
para string_view
.
Então, eu mudo obedientemente meu código, de acordo com a nova interface. Infelizmente, o que eu tenho que passar é um parâmetro std :: string e algo que é um valor de retorno std :: string. Então, meu código mudou de algo assim:
void one_time_setup(const std::string & p1, int p2) {
api_class api;
api.setup (p1, special_number_to_string(p2));
}
para
void one_time_setup(const std::string & p1, int p2) {
api_class api;
const std::string p2_storage(special_number_to_string(p2));
api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size()));
}
Eu realmente não vejo o que esta mudança me comprou como o cliente API, que não seja mais código (possivelmente para estragar). A chamada da API é menos segura (devido ao fato de a API não possuir mais o armazenamento de seus parâmetros), provavelmente salvou o trabalho do meu programa 0 (devido às otimizações de movimentação que os compiladores podem fazer agora) e, mesmo se salvou o trabalho, isso seria apenas algumas alocações que nunca serão e nunca seriam feitas após a inicialização ou em um grande loop em algum lugar. Não para esta API.
No entanto, essa abordagem parece seguir os conselhos que eu vejo em outros lugares, por exemplo, esta resposta :
Como um aparte, desde o C ++ 17, você deve evitar passar uma const std :: string e a favor de uma std :: string_view:
Acho esse conselho surpreendente, pois parece defender universalmente a substituição de um objeto relativamente seguro por um objeto menos seguro (basicamente um ponteiro e comprimento glorificados), principalmente para fins de otimização.
Então, quando string_view deve ser usado, e quando não deveria?
fonte
std::string_view
construtor diretamente, basta passar as strings para o método que recebe umstd::string_view
diretamente e ele será convertido automaticamente.<string>
cabeçalho e acontece automaticamente. Esse código é enganador e errado.Respostas:
std::string
(non-const, non-ref). Essa opção oferece a opção de mover explicitamente um valor também, se você souber que ele nunca será usado novamente no contexto de chamada.std::string_view
Nesse caso, use (const, non-ref), porque issostring_view
pode ser feito facilmentestd::string
echar*
sem problemas e sem fazer uma cópia. Isso deve substituir todos osconst std::string&
parâmetros.Em última análise, você nunca precisará chamar o
std::string_view
construtor como você é.std::string
possui um operador de conversão que lida com a conversão automaticamente.fonte
std::string_view
facilitar a utilização. Se um desenvolvedor o usa mal em uma situação de propriedade, isso é um erro de programação.std::string_view
é estritamente não proprietário.const, non-ref
? O parâmetro sendo const é de uso específico, mas em geral é razoável como não-const. E você perdeu 3. Pode aceitar fatiasconst std::string_view &
no lugar deconst std::string &
?A
std::string_view
traz alguns dos benefícios de aconst char*
para C ++: ao contráriostd::string
, um string_viewstd::string&
.Isso significa que um string_view geralmente pode evitar cópias, sem precisar lidar com ponteiros brutos.
No código moderno,
std::string_view
deve substituir quase todos os usos deconst std::string&
parâmetros de função. Essa alteração deve ser compatível com a fonte, poisstd::string
declara um operador de conversão comostd::string_view
.Só porque uma exibição de sequência não ajuda em seu caso de uso específico, em que você precisa criar uma sequência de qualquer maneira, não significa que seja uma má ideia em geral. A biblioteca padrão C ++ tende a ser otimizada por generalidade e não por conveniência. O argumento "menos seguro" não é válido, pois não deve ser necessário criar você mesmo a visualização de string.
fonte
std::string_view
é a ausência de umc_str()
método, resultando emstd::string
objetos intermediários desnecessários que precisam ser construídos e alocados. Isso é especialmente um problema nas APIs de baixo nível.abcdef\0
e uma exibição de string que aponte para acde
substring, não haverá um caractere zero após oe
- a string original possui umf
. O padrão também observa: “data () pode retornar um ponteiro para um buffer que não possui terminação nula. Por isso, é normalmente um erro para passar dados () para uma função que leva apenas um gráfico const * e espera uma string terminada em nulo “.Eu acho que isso é um pouco mal entendido do objetivo disso. Embora seja uma "otimização", você deve realmente pensar nisso como se livrar de ter que usar um
std::string
.Usuários de C ++ criaram dezenas de diferentes classes de strings. Classes de string de comprimento fixo, classes otimizadas para SSO com o tamanho do buffer como parâmetro do modelo, classes de string que armazenam um valor de hash usado para compará-las, etc. Algumas pessoas até usam strings baseadas em COW. Se há uma coisa que os programadores de C ++ gostam de fazer, é escrever classes de string.
E isso ignora as strings criadas e pertencentes às bibliotecas C. N nu
char*
, talvez com algum tamanho.Portanto, se você estiver escrevendo alguma biblioteca e fizer uma
const std::string&
, agora o usuário precisará pegar qualquer string que estiver usando e copiá-la para astd::string
. Talvez dezenas de vezes.Se você deseja acessar a
std::string
interface específica de cadeia de caracteres, por que você deve copiar a string? Isso é um desperdício.Os principais motivos para não usar a
string_view
como parâmetro são:Se seu objetivo final é passar a string para uma interface que use uma string terminada em NUL (
fopen
, etc).std::string
é garantido para ser NUL terminado;string_view
não é. E é muito fácil criar uma exibição de substring para torná-la sem terminação NUL; sub-string astd::string
copiará a subcadeia em um intervalo terminado por NUL.Eu escrevi um tipo especial de estilo string_view terminado em NUL para exatamente esse cenário. Você pode executar a maioria das operações, mas não as que quebram seu status de NUL (aparando a partir do final, por exemplo).
Problemas ao longo da vida. Se você realmente precisa copiar isso
std::string
ou, caso contrário, a matriz de caracteres sobreviver à chamada de função, é melhor declarar isso com antecedência usando aconst std::string &
. Ou apenas umstd::string
parâmetro como value. Dessa forma, se eles já tiverem essa sequência, você poderá reivindicar a propriedade imediatamente, e o chamador poderá passar para a sequência se não precisar manter uma cópia dela.fonte
string_view
é um tipo de lingua franca que pode funcionar com qualquer coisa.string_view
, é fácil.