Recentemente, recebi sugestões de uso span<T>
no meu código ou vi algumas respostas aqui no site que usam span
supostamente algum tipo de contêiner. Mas - não consigo encontrar nada parecido na biblioteca padrão do C ++ 17.
Então, o que é misterioso span<T>
e por que (ou quando) é uma boa ideia usá-lo se não é padrão?
std::span
foi proposto em 2017. Aplica-se ao C ++ 17 ou C ++ 20. Consulte também P0122R5, visualizações span: safe-safe para seqüências de objetos . Deseja realmente segmentar esse idioma? Levará anos até que os compiladores os recuperem.gsl::span
e nãostd::span
. Veja também minha resposta abaixo.Respostas:
O que é isso?
A
span<T>
é:T
em algum lugar da memória.struct { T * ptr; std::size_t length; }
com um monte de métodos de conveniência.Era conhecido anteriormente como
array_view
e até mais cedo comoarray_ref
.Quando devo usá-lo?
Primeiro, quando não usá-lo:
std::sort
,std::find_if
,std::copy
e todas essas funções de super-generic templated.Agora, quando realmente usá-lo:
Por que devo usá-lo? Por que isso é uma coisa boa?
Oh, vãos são incríveis! Usando um
span
...significa que você pode trabalhar com essa combinação de ponteiro + comprimento / início + fim, como faria com um contêiner de biblioteca padrão sofisticado e sofisticado, por exemplo:
for (auto& x : my_span) { /* do stuff */ }
std::find_if(my_span.begin(), my_span.end(), some_predicate);
... mas com absolutamente nenhuma das despesas gerais incorridas pela maioria das classes de contêineres.
permite que o compilador faça mais trabalho para você às vezes. Por exemplo, isto:
torna-se este:
... o que fará o que você gostaria que ele fizesse. Veja também a Diretriz P.5 .
é a alternativa razoável para passar
const vector<T>&
para funções quando você espera que seus dados sejam contíguos na memória. Chega de ser repreendido por grandes e poderosos gurus de C ++!span
, os métodos terão algum código de verificação de limites dentro de#ifndef NDEBUG
...#endif
)Há ainda mais motivação para usar
span
s, que você pode encontrar nas diretrizes principais do C ++ - mas você percebe a diferença.Por que não está na biblioteca padrão (a partir do C ++ 17)?
Está na biblioteca padrão - mas apenas a partir do C ++ 20. O motivo é que ele ainda é bastante novo em sua forma atual, concebido em conjunto com o projeto de diretrizes principais do C ++ , que só vem se formando desde 2015. (Embora, como comentam os comentaristas, ele tenha um histórico anterior).
Então, como eu o uso se ainda não estiver na biblioteca padrão?
Faz parte da Biblioteca de suporte das diretrizes principais (GSL). Implementações:
gsl/span
span<T>
.A implementação da GSL geralmente assume uma plataforma que implementa o suporte ao C ++ 14 [ 14 ]. Essas implementações alternativas de cabeçalho único não dependem dos recursos da GSL:
martinmoene/span-lite
requer C ++ 98 ou posteriortcbrindle/span
requer C ++ 11 ou posteriorObserve que essas implementações de span diferentes têm algumas diferenças em quais métodos / funções de suporte eles vêm; e eles também podem diferir um pouco da versão que entra na biblioteca padrão em C ++ 20.
Leitura adicional: Você pode encontrar todos os detalhes e considerações de design na proposta oficial final antes de C ++ 17, P0122R7: span: visualizações seguras de limites para seqüências de objetos por Neal Macintosh e Stephan J. Lavavej. É um pouco longo, no entanto. Além disso, no C ++ 20, a semântica da comparação de span foi alterada (seguindo este pequeno artigo de Tony van Eerd).
fonte
std::cout << sizeof(buffer) << '\n'
e você verá 100 sizeof (int) 's.std::array
é um contêiner, possui os valores.span
não é proprietáriostd::array
é um animal completamente diferente. Seu comprimento é fixo no tempo de compilação e é um tipo de valor em vez de um tipo de referência, como Caleth explicou.@einpoklum faz um bom trabalho ao apresentar o que
span
é em sua resposta aqui . No entanto, mesmo depois de ler sua resposta, é fácil para alguém novo se estender ainda ter uma sequência de perguntas que não são totalmente respondidas, como as seguintes:span
diferença de uma matriz C? Por que não usar apenas um desses? Parece que é apenas um daqueles com o tamanho conhecido também ...std::array
, como éspan
diferente disso?std::vector
como umstd::array
também?span
?Então, aqui está uma clareza adicional sobre isso:
CITAÇÃO DIRETA DE SUA RESPOSTA - COM MINHAS ADIÇÕES EM NEGRITO :
Essas partes ousadas são críticas para o entendimento, portanto, não as perca ou as interprete mal! A
span
NÃO é uma matriz C de estruturas, nem é uma estrutura de uma matriz C do tipoT
mais o comprimento da matriz (isso seria essencialmente o que ostd::array
contêiner é), NOR é uma matriz C de estruturas de ponteiros para digitarT
mais o comprimento, mas é uma estrutura única que contém um ponteiro para digitarT
e o comprimento , que é o número de elementos (do tipoT
) no bloco de memória contíguo para o qual o ponteiro para o tipoT
aponta! Dessa forma, a única sobrecarga que você adicionou usando umspan
são as variáveis para armazenar o ponteiro e o comprimento, e quaisquer funções de acessador de conveniência que você utilize que sejamspan
fornecidas.Isso é UNLIKE a
std::array<>
porque, nastd::array<>
verdade, aloca memória para todo o bloco contíguo, e é UNLIKEstd::vector<>
porque astd::vector
é basicamente apenas umstd::array
que também produz crescimento dinâmico (geralmente dobrando de tamanho) cada vez que é preenchido e você tenta adicionar algo a ele . Astd::array
é de tamanho fixo e aspan
nem gerencia a memória do bloco para o qual aponta, apenas aponta para o bloco de memória, sabe quanto tempo o bloco de memória tem, sabe qual é o tipo de dados em um array C na memória e fornece funções convenientes de acessador para trabalhar com os elementos nessa memória contígua .Ele é parte do padrão C ++:
std::span
faz parte do padrão C ++ a partir do C ++ 20. Você pode ler a documentação aqui: https://en.cppreference.com/w/cpp/container/span . Para ver como usar o Googleabsl::Span<T>(array, length)
no C ++ 11 ou mais recente hoje , veja abaixo.Descrições de resumo e referências principais:
std::span<T, Extent>
(Extent
= "o número de elementos na sequência, oustd::dynamic_extent
se dinâmico". Um período apenas aponta para a memória e facilita o acesso, mas NÃO o gerencia!):std::array<T, N>
(observe que ele tem um tamanho fixoN
!):std::vector<T>
(cresce automaticamente de tamanho dinamicamente, conforme necessário):Como posso usar
span
no C ++ 11 ou posterior hoje ?O Google abriu suas bibliotecas C ++ 11 internas na forma de sua biblioteca "Abseil". Esta biblioteca destina-se a fornecer recursos C ++ 14 a C ++ 20 e além, que funcionam no C ++ 11 e posterior, para que você possa usar os recursos de amanhã hoje. Eles dizem:
Aqui estão alguns recursos e links importantes:
span.h
cabeçalho eabsl::Span<T>(array, length)
classe de modelo: https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189fonte