C++11: Métodos Modernos da std::string

por Fabio A. Mazzarino

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.