C++17中std::any的使用

      类sdk:any提供类型安全的容器来存储任何类型的单个值。通俗地说,std::any是一个容器,可以在其中存储任何值(或用户数据),而无需担心类型安全。void*的功能有限,仅存储指针类型,被视为不安全模式。std::any可以被视为void*的类型安全替代品。
      std::any初始化:拷贝初始化;使用参数化构造函数;大括号初始值设定(brace initializer);使用赋值运算符;使用std::make_any。
      必须使用std::any_cast<type>(any_var)函数将any_var值转换为原始类型。std::any_cast<type>(any_var)函数有一些重载,它可以返回副本、引用或指针,具体取决于调用方式。如果存储值的类型不是尝试转换的类型,则编译器将抛出std::bad_any_cast异常或返回nullptr转换期间的类型必须与原始类型完全相同

int test_any_init()
{
	// copy initialisation
	std::any value = 66; // 推荐: std::any value = std::make_any<int>(66); // std::make_any:类型安全、异常安全
	std::cout << "value: " << std::any_cast<int>(value) << "\n"; // value: 66

	// assignment operator
	value = "China";
	std::cout << "value: " << std::any_cast<const char*>(value) << "\n"; // value: China

	// parametrized constructor
	std::any value2(88.);
	std::cout << "value2: " << std::any_cast<double>(value2) << "\n"; // value2: 88

	// brace initializer
	try {
		std::any value3{ "China" };
		std::cout << "value3: " << std::any_cast<std::string>(value3) << "\n"; // std::any_cast<const char*>(value3)
	} catch (std::bad_any_cast& e) {
		std::cout << "Error: " << e.what() << "\n"; // value3: Error: Bad any_cast
	}

	auto value4 = std::make_any<std::string>("Beijing");
	std::cout << "value4: " << std::any_cast<std::string&>(value4) << "\n"; // value4: Beijing 推荐转换为引用类型来避免创建临时对象

	std::string str = "Tianjin";
	std::any value5 = std::move(str);
	std::cout << "value5: " << std::any_cast<std::string&>(value5) << "\n"; // value5: Tianjin

	return 0;
}

      std::any的成员函数
      (1).emplace:改变存储的对象,直接构造新对象;
      (2).reset:通过调用对象的析构函数来销毁存储的对象;
      (3).has_value:用于检查对象是否存储值;
      (4).type:返回一个type_info结构体,可用于获取存储对象的属性,如存储值的类型ID

int test_any_member_functions()
{
	// emplace, type
	std::any value = 6;
	std::cout << "value: " << std::any_cast<int>(value) << "\n"; // value: 6
	std::cout << "type name: " << value.type().name() << "\n"; // type name: int(windows), i(linux)

	auto& tmp = std::any_cast<int&>(value); // 引用
	tmp = 8;
	std::cout << "value: " << std::any_cast<int>(value) << "\n"; // value: 8
	std::any_cast<int&>(value) = 10;
	std::cout << "value: " << std::any_cast<int>(value) << "\n"; // value: 10

	auto ptr = std::any_cast<int>(&value); // 指针
	std::cout << "value: " << *ptr << "\n"; // value: 10

	// 避免抛异常
	auto ptr2 = std::any_cast<std::string>(&value);
	if (ptr2 == nullptr)
		std::cout << "value dons't contain a string\n"; // value dons't contain a string

	value.emplace<std::string>("China");
	std::cout << "value: " << std::any_cast<std::string>(value) << "\n"; // value: China
	std::cout << "type name: " << value.type().name() << "\n"; // windows: type name: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
															   // linux:   type name: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE

	if (value.type() == typeid(std::string))
		std::cout << "value type is std::string\n"; // value type is std::string

	// reset, has_value
	if (value.has_value()) std::cout << "value found\n"; // value found
	value.reset();
	if (!value.has_value()) std::cout << "no value found\n"; // no value found

	std::any tmp2;
	if (!tmp2.has_value()) std::cout << "tmp2 no value found\n"; // tmp2 no value found

	// std::any的主要问题是额外的动态内存分配
	std::cout << "size(any): " << sizeof(std::any) << "\n"; // size(any): 64(windows 10 vs2022), 16(ubuntu22.04 g++ 11.4)

	value = std::vector<int>{ 1, 2, 3 };
	std::cout << "value size: " << std::any_cast<std::vector<int>&>(value).size() << "\n"; // value size: 3

	return 0;
}

      执行结果如下图所示:注意:windows与linux上的差异

      尽管std::any为C++提供了很大的灵活性,但std::any的主要问题是额外的动态内存分配(堆内存)。由于容器不知道所包含的对象,因此动态分配成为任何对象都必须的。
      如果你了解所存储的类型(除了所存储的类型必须是可复制的这一事实之外),那么std::any可能不是合适的工具:它的灵活性会带来性能成本。如果恰好存在一个这样的类型T,则应该使用std::Optional。如果要存储的类型始终是具有特定签名的函数对象(例如回调),那么你需要std::function。如果你只需要存储编译时固定的某个集合中的类型,std::variant是一个不错的选择

      GitHubhttps://github.com/fengbingchun/Messy_Test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值