30.03
2021
No post de hoje vamos citar os novos métodos da std::string no C++11, alguns são muito bacanas e implementam funcionalidades populares em outras linguagens. Vamos avaliá-las conforme a versão em que estão disponível com exemplos.
front() e back()
Esses dois métodos recuperam, respectivamente, o primeiro e o último caractere, seu funcionamento é bem simples:
std::string s1 = "12345";
std::cout << s1.front() << " - " << s1.back() << std::endl;
O trecho de código acima vai gerar a seguinte saída:
1 - 5
cbegin(), crbegin(), cend() e crend()
Equivalentes ao begin(), rbegin(), end() e rend(), porém retornam const iterators, ou seja, seu conteúdo não pode ser alterado.
std::string s2 = "abcde";
for (auto it2 = s2.begin(); it2 != s2.cend(); it2++, c++)
*it2 = 'A';
O código acima compila com sucesso. Porém se alterarmos a chamada do método begin() para cbegin() teremos uma falha de sintaxe, o compilador não vai aceitar alterar o conteúdo apontado pelo iterator, pois o mesmo é const. Note que usamos cend() para comparar it2 com o fim da string.
shrink_to_fit()
Nem todo mundo sabe, mas std::string manter um buffer que vai sendo incrementado conforme a string vai crescendo, e a alocação é por bloco, aumentando o tamanho do buffer mais que o necessário para caber a string. Para evitar essa alocação desnecessária basta utilizar o método shring_to_fit(). Vamos a um exemplo:
std::string s3 = "";
std::cout << "size: " << s3.size() << " capacity: " << s3.capacity() << std::endl;
for (int c = 'a'; c <= 'z'; c++)
s3.push_back(c);
std::cout << "size: " << s3.size() << " capacity: " << s3.capacity() << std::endl;
s3.shrink_to_fit();
std::cout << "size: " << s3.size() << " capacity: " << s3.capacity() << std::endl;
s3 = "abc";
std::cout << "size: " << s3.size() << " capacity: " << s3.capacity() << std::endl;
s3.shrink_to_fit();
std::cout << "size: " << s3.size() << " capacity: " << s3.capacity() << std::endl;
O código acima vai imprimir a seguinte saída:
size: 0 capacity: 15
size: 26 capacity: 30
size: 26 capacity: 26
size: 3 capacity: 26
size: 3 capacity: 15
Já na alocação o objeto aloca 15 bytes, mesmo sem ter nenhum conteúdo. Depois de adicionado 26 caracteres o buffer ficou com 30 caracteres. Mas depois de executar o método shrink_to_fit() o buffer passou a ficar com 26 caracteres.
Em seguida atribuímos 3 caracteres para a string, e a capacidade do buffer se manteve em 26 caracteres. O que foi reduzido para 15 caracteres, o mínimo, após o método shrink_to_fit().
pop_back()
Este é o complemento do push_back(), retirando o último caractere da string. Vamos ver um exemplo:
std::string s4 = "abcd";
std::cout << "back(): " << s4.back() << std::endl;
s4.pop_back();
std::cout << "back(): " << s4.back() << std::endl;
Que irá gerar a seginte saída:
back(): d
back(): c
sto*()
Não são métodos, mas um conjunto de funções, fazem a conversão de strings em representações numéricas. São ao todo 8 funções:
- stoi() – conversão para int;
- stol() – conversão para long;
- stoll() – conversão para long long;
- stoul() – conversão para unsigned long;
- stoull() – conversão para unsigned long long;
- stof() – conversão para float;
- stod() – conversão para double;
- stold() – conversão para long double;
Uma grande vantagem sobre as funções da linguagem C, atoi(), por exemplo é a possibilidade de fazer parser parcial, ou seja, vários números em uma única string podem ser interpretados um a um. Outra vantagem é a definição da base numérica a ser utilizada. Veja os exemplos:
std::string s5 = "1337";
std::cout << stoi(s5) << std::endl;
std::string s6 = "31 53 75";
std::size_t p;
std::cout << stoi(s6, &p) << " - p: " << p << std::endl;
std::cout << stoi(s6.substr(p), &p) << " - p: " << p << std::endl;
std::string s7 = "0xffff";
std::cout << stoi(s7, NULL, 16) << std::endl;
Que vai gerar a saída:
1337
31 - p: 2
53 - p: 3
65535
Note a conversão da string s6, através da utilização do segundo parâmetro é possível converter todos os números da string, individualmente.
to_string()
As funções to_string() fazem a conversão de números para string, cada função aceita um único parâmetro numérico que podem ser dos tipos:
- int, long e long long;
- unsigned, unsigned long e unsigned long long;
- float, double e long double.
Basicamente os mesmos tipos suportados pelas funções sto*(). Com essas funções não é mais necessário criar um stream para fazer a conversão, tal qual era necessário até C++03. Um breve exemplo:
std::string s8 = std::to_string(1337);
std::cout << s8 << std::endl;
Vai gerar a saída:
1337
C++20
O padrão C++20 tem outra funções muito interessantes, tais como:
- starts_with() – verifica se a string começa com um conjunto de caracteres
- ends_with() – verifica se a string termina com um conjunto de caracteres
- contains() – verifica se a string contém um conjunto de caracteres
- operator <=>() – que encapsula o método compare()
- erase() e erase_if() – remove um conjunto de caracteres da string
O grande problema de abordarmos C++20 é que ainda não há suporte total nos compiladores mais populares, então, por enquanto, vamos só citar. Quem sabe no futuro poderemos mostrar uns bons exemplos.