Eu estava olhando um código de um sistema e me deparei com um trecho que me fez torcer o nariz. O código funcionava, mas imediatamente vi dois problemas potenciais:
https://gist.github.com/thiagomg/fb38cc780769449dc162
Eu suponho que a pessoa que desenvolveu o código fez dessa forma para pegar os itens que estavam no vector, excluindo os itens da borda (0:n), mas como seria essa implementação da forma STL de se programar ?
https://gist.github.com/thiagomg/8f910117dcbc4461a7e0
Todas elas tem um problema com relação à implementação original. A implementação original pega o range de [1:size-1). Estas formas que eu apresentei pegam o range de [0:size). Como fazer então ?
A forma mais inocente e com os mesmos problemas da implementação que eu vi seria:
https://gist.github.com/thiagomg/60bf3f9b29f6eb568fd5
Se o tamanho do vector for 0, msgs.cbegin() == msgs.cend(), e teremos um problema, pois msgs.cbegin()+1 estaria apontando para uma região da memória mais adiante da apontada por msgs.cend()-1. Vemos também que os outros exemplos de ranged-for não nos dão a possibilidade de mudar o intervalo com offsets. Qual seria a solução então ?
A definição de um container no qual é possível executar iterações, (grosseiramente) é um objeto que possui as funções begin e end. Então, fiz uma solução interessante para o caso, algo parecido ou no estilo de uma view.
Para começar, precisamos de uma estrutura que implemente um range
https://gist.github.com/thiagomg/ffbe23711b8abc5c001d
Agora já temos a nossa estrutura contendo begin e end e dois iteradores. Só falta criarmos uma função que aponte os iteradores para um container definindo o range [1:size-1)
https://gist.github.com/thiagomg/b863b666c01d6ea26e56
Temos agora uma função que retorna de forma segura o range [1:size-1) mesmo quando o vetor é vazio ou contém menos de dois elementos.
Segue abaixo um exemplo de uso da função narrow_range
https://gist.github.com/thiagomg/5e253b31be483d14bae0
Fontes:
https://github.com/SimplyCpp/examples/blob/master/loop1.cpp
https://github.com/SimplyCpp/examples/blob/master/loop2.cpp
- Bug de int/unsigned int
- Um vector::size() - 1
- Se size for 0, o resultado será 4294967295 ou 0xFFFFFFFF!
- Código confuso e facilmente quebrável
- msgs[count] - Não tem offset dinâmico
- Um count inválido pode quebrar o programa
https://gist.github.com/thiagomg/fb38cc780769449dc162
Eu suponho que a pessoa que desenvolveu o código fez dessa forma para pegar os itens que estavam no vector, excluindo os itens da borda (0:n), mas como seria essa implementação da forma STL de se programar ?
Três possibilidades
https://gist.github.com/thiagomg/8f910117dcbc4461a7e0
Todas elas tem um problema com relação à implementação original. A implementação original pega o range de [1:size-1). Estas formas que eu apresentei pegam o range de [0:size). Como fazer então ?
A forma mais inocente e com os mesmos problemas da implementação que eu vi seria:
https://gist.github.com/thiagomg/60bf3f9b29f6eb568fd5
Se o tamanho do vector for 0, msgs.cbegin() == msgs.cend(), e teremos um problema, pois msgs.cbegin()+1 estaria apontando para uma região da memória mais adiante da apontada por msgs.cend()-1. Vemos também que os outros exemplos de ranged-for não nos dão a possibilidade de mudar o intervalo com offsets. Qual seria a solução então ?
A definição de um container no qual é possível executar iterações, (grosseiramente) é um objeto que possui as funções begin e end. Então, fiz uma solução interessante para o caso, algo parecido ou no estilo de uma view.
Solução adequada - Range!
Para começar, precisamos de uma estrutura que implemente um range
https://gist.github.com/thiagomg/ffbe23711b8abc5c001d
Agora já temos a nossa estrutura contendo begin e end e dois iteradores. Só falta criarmos uma função que aponte os iteradores para um container definindo o range [1:size-1)
https://gist.github.com/thiagomg/b863b666c01d6ea26e56
Temos agora uma função que retorna de forma segura o range [1:size-1) mesmo quando o vetor é vazio ou contém menos de dois elementos.
Segue abaixo um exemplo de uso da função narrow_range
https://gist.github.com/thiagomg/5e253b31be483d14bae0
Fontes:
https://github.com/SimplyCpp/examples/blob/master/loop1.cpp
https://github.com/SimplyCpp/examples/blob/master/loop2.cpp
[…] “Um problema que ocorre frequentemente é a escrita de códigos que são facilmente quebráveis. O uso de offsets acaba tornando as iterações frágeis. Este post mostra uma forma de fazer as iterações de forma segura e rápida em C++” [referência: simplycpp.com] […]
ResponderExcluir