DEV Community

Cover image for Utilize std::any do C++ Moderno nos seus projetos
Marcos Oliveira
Marcos Oliveira

Posted on

1

Utilize std::any do C++ Moderno nos seus projetos

Dê adeus de uma vez por todas ao void*.


std::any é um recurso da biblioteca padrão C++ que foi introduzido no C++17.

Este componente pertence ao conjunto de classes de contêineres com segurança de tipo, fornecendo um meio seguro para armazenar e manipular valores de qualquer tipo.

Ele é especialmente útil quando você precisa lidar com situações em que o tipo da variável pode(pleonasmo): variar! 😃

Aí você diz:

— Ah, cara! De boa. Para esses casos eu uso o void *.

Sim, realmente você tem razão, mas você já viu como a nova geração está em relação a segurança de memória ???

Lembrando que o termo segurança é usado em Português, pois não existe uma palavra que se adeque a tradução para Safe, ou seja: Safe Seguro)! 😛

Sem dizer que void * é realmente perigoso!

Se você fizer isso, funciona:

void * some_data; // Péssima ideia

std::string str = "Oi";
int x = 3;
decltype(x) y = 6;

some_data = &str;
std::cout << *(std::string*)some_data << '\n';

some_data = &x;
std::cout << *(int*)some_data << '\n';

some_data = &y;
std::cout << "Tipo de y: " << typeid(y).name() << '\n'; // include typeinfo
Enter fullscreen mode Exit fullscreen mode

Mas, a chance de isso dar mer%$a é grande! Ao final do uso dessas variáveis, some_data vai continuar existindo, ou seja, tempo de vida indefinido!

E é para subsitituir o void* que o std::any foi criado no C++ Moderno que, com certeza, é totalmente Safe!

Em outras palavras, ele é um wrapper que encapsula sua variável para um shared_ptr(ponteiros inteligentes) da vida! Sim, e existe até um std::make_any!!!


Como utilizar o std::any

Primeiramente você precisa incluir o cabeçalho dele:

Logicamente, só funciona a partir do C++17 como foi dito no início!

#include <any>
Enter fullscreen mode Exit fullscreen mode

E agora o mesmo código que foi apresentado acima, mas usando std::any:

#include <iostream>
#include <any>

int main(){
  std::any some_data;

  std::string str = "Oi";
  int x = 3;
  auto y = std::make_any<decltype(x)>(6);

  some_data = str;
  std::cout << std::any_cast<std::string>(some_data) << '\n';

  some_data = x;
  std::cout << std::any_cast<int>(some_data) << '\n';

  some_data = y;
  std::cout << "Tipo de y: " << some_data.type().name() << '\n';
}
Enter fullscreen mode Exit fullscreen mode

No código acima vimos que:

  • std::any some_data; - Declara a variável;
  • std::any_cast<T>(some_data) - Converte para o tipo desejado;
  • std::make_any<T> - Outra forma de criar objetos;
  • some_data.type().name() - Obtém o tipo de dado sem precisar de typeinfo.

E você pode usar pra absolutamente tudo: std::vector, Lambda e tudo que existir de tipo de dado!

E o cara pergunta outra coisa:

— Tá! E se eu quiser acabar o tempo de vida do std::any manualmente?

Basta usar a estrutura de união reset ou até mesmo com o operador de incialização:

some_data.reset();
// Ou
some_data = {};
Enter fullscreen mode Exit fullscreen mode

— E pra verificar se std::any está vazio?
Use has_value():

std::cout << (some_data.has_value() ? "Cheio!" : "Vazio.") << '\n';
Enter fullscreen mode Exit fullscreen mode

O type() sem união com name() pode ser usado para comparar tipos:

std::cout << (some_data.type() == typeid(void)) << '\n'; // 0 pra false
std::cout << (some_data.type() == typeid(int)) << '\n'; // 1 pra true
Enter fullscreen mode Exit fullscreen mode

Para usar os nomes booleanos use: std::cout << std::boolalpha << (some_data.type() == typeid(int)) << '\n';.

Para lançar exceções você deve usar o std::bad_any_cast:

try {

  std::any any_str("Oiii");
  auto my_any{ std::make_any<std::string>(any_str.type().name()) };
  std::cout << std::any_cast<std::string>(my_any) << '\n';

}catch (const std::bad_any_cast& e) {
  std::cerr << "Error: " << e.what() << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

Para verificar se realmente tudo está entre os conformes, nunca se esqueça de usar as flags para seu compilador: -Wall -Wextra -pedantic -g -fsanitize=address.


Além de totalmente SAFE, o std::any é muito prático e uma mão na roda!

Tinha um projeto da empresa que eu estava desenvolvendo, que passava um argumento de função e podia ser qualquer tipo, mas o retorno da função era std::string concatenada ao nome do objeto recebido.

E alguém havia criado um baita de um switch case para converter para std::string(bizarro!), eu subsititui para recebimento de parâmetro para std::any e converti com std::any_cast<std::string> e resolvi de forma: Moderna, Safe e Like a Boss! Exatamente isso que std::any é!!! 😃

Para mais informações acesse: https://en.cppreference.com/w/cpp/utility/any

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay