c++ std::any怎么用 如何存储任意类型数据

来源:网站建设作者:盲改大师头衔:程序员
导读:本期聚焦于小伙伴创作的《c++ std::any怎么用 如何存储任意类型数据》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《c++ std::any怎么用 如何存储任意类型数据》有用,将其分享出去将是对创作者最好的鼓励。

std::any是C++17标准新增的类型,定义在<any>头文件中,它允许我们在运行时存储任意可拷贝构造的类型实例,并且可以在后续操作中检查存储的类型是否符合预期,相比传统的void*指针方案,它具备更好的类型安全性。

c++ std::any怎么用 如何存储任意类型数据

std::any的基本使用流程

使用std::any存储和读取数据主要分为三个步骤:存入数据、判断存储类型、取出数据。下面通过简单示例说明基础用法。

1. 存入数据

我们可以直接通过赋值或者构造函数将任意可拷贝类型的数据存入std::any对象中,支持内置类型、自定义类型、标准库容器等。

#include <any>
#include <iostream>
#include <string>
#include <vector>

// 自定义可拷贝类型
struct User {
    std::string name;
    int age;
};

int main() {
    // 存储内置类型
    std::any a1 = 10;
    std::any a2 = 3.14;
    std::any a3 = std::string("hello std::any");
    
    // 存储自定义类型
    std::any a4 = User{"张三", 25};
    
    // 存储标准库容器
    std::any a5 = std::vector<int>{1, 2, 3, 4};
    
    return 0;
}

2. 判断存储的类型

在取出数据之前,我们需要先确认std::any对象中存储的类型是否符合预期,避免错误的类型转换导致异常。可以使用type()方法获取存储类型的type_info,再和目标的type_info比较。

#include <any>
#include <iostream>
#include <string>
#include <typeinfo>

int main() {
    std::any a = 100;
    
    // 判断存储的是否是int类型
    if (a.type() == typeid(int)) {
        std::cout << "存储的类型是int" << std::endl;
    } else {
        std::cout << "存储的类型不是int" << std::endl;
    }
    
    // 判断存储的是否是string类型
    if (a.type() == typeid(std::string)) {
        std::cout << "存储的类型是string" << std::endl;
    }
    
    return 0;
}

3. 取出数据

取出数据需要使用std::any_cast函数,它支持两种使用方式:一种是传入std::any对象的指针,转换失败返回空指针;另一种是传入std::any对象的引用,转换失败会抛出std::bad_any_cast异常。

#include <any>
#include <iostream>
#include <string>

int main() {
    std::any a = std::string("test data");
    
    // 方式1:指针形式,失败返回nullptr
    std::string* ptr = std::any_cast<std::string>(&a);
    if (ptr != nullptr) {
        std::cout << "指针方式取出数据:" << *ptr << std::endl;
    }
    
    // 方式2:引用形式,失败抛出异常
    try {
        std::string val = std::any_cast<std::string>(a);
        std::cout << "引用方式取出数据:" << val << std::endl;
    } catch (const std::bad_any_cast& e) {
        std::cout << "类型转换失败:" << e.what() << std::endl;
    }
    
    // 错误类型转换示例
    try {
        int wrong_val = std::any_cast<int>(a);
    } catch (const std::bad_any_cast& e) {
        std::cout << "错误转换捕获:" << e.what() << std::endl;
    }
    
    return 0;
}

std::any的常用操作

判断是否有值

可以使用has_value()方法判断std::any对象是否存储了有效数据,空对象调用该方法会返回false。

#include <any>
#include <iostream>

int main() {
    std::any a1;
    std::any a2 = 20;
    
    std::cout << "a1是否有值:" << (a1.has_value() ? "是" : "否") << std::endl;
    std::cout << "a2是否有值:" << (a2.has_value() ? "是" : "否") << std::endl;
    
    return 0;
}

清空存储的数据

调用reset()方法可以清空std::any对象中存储的数据,清空后has_value()会返回false。

#include <any>
#include <iostream>

int main() {
    std::any a = 100;
    std::cout << "清空前是否有值:" << (a.has_value() ? "是" : "否") << std::endl;
    
    a.reset();
    std::cout << "清空后是否有值:" << (a.has_value() ? "是" : "否") << std::endl;
    
    return 0;
}

替换存储的数据

可以直接对std::any对象赋值新的数据,会自动替换之前存储的内容,类型也可以和之前不同。

#include <any>
#include <iostream>
#include <string>

int main() {
    std::any a = 10;
    std::cout << "初始类型:" << a.type().name() << std::endl;
    
    // 替换为string类型
    a = std::string("new value");
    std::cout << "替换后类型:" << a.type().name() << std::endl;
    std::cout << "替换后的值:" << std::any_cast<std::string>(a) << std::endl;
    
    return 0;
}

使用注意事项

  • std::any只能存储可拷贝构造的类型,如果自定义类型没有拷贝构造函数,无法存入std::any。
  • 取出数据时的类型必须和存储的类型完全匹配,比如存储的是const char*,不能用std::string去转换,否则会抛出异常。
  • 不要存储引用类型或者指针指向临时对象,避免std::any存储的对象失效导致未定义行为。
  • std::any会带来一定的性能开销,因为它内部需要管理动态内存和类型信息,如果对性能要求极高的场景,需要谨慎使用。

实际应用场景

std::any适合用在需要临时存储不确定类型的场景,比如通用配置项存储、回调函数参数传递、异构数据容器等。下面是一个简单的通用配置存储示例:

#include <any>
#include <iostream>
#include <string>
#include <unordered_map>

// 通用配置容器,key是配置名,value是配置值
std::unordered_map<std::string, std::any> config_map;

// 设置配置
void set_config(const std::string& key, const std::any& value) {
    config_map[key] = value;
}

// 获取配置
template <typename T>
T get_config(const std::string& key) {
    auto it = config_map.find(key);
    if (it == config_map.end()) {
        throw std::runtime_error("配置不存在");
    }
    return std::any_cast<T>(it->second);
}

int main() {
    // 设置不同类型的配置
    set_config("max_count", 100);
    set_config("app_name", std::string("test_app"));
    set_config("enable_log", true);
    
    // 读取配置
    int max_count = get_config<int>("max_count");
    std::string app_name = get_config<std::string>("app_name");
    bool enable_log = get_config<bool>("enable_log");
    
    std::cout << "max_count: " << max_count << std::endl;
    std::cout << "app_name: " << app_name << std::endl;
    std::cout << "enable_log: " << (enable_log ? "true" : "false") << std::endl;
    
    return 0;
}

std::anyC++任意类型存储类型安全修改时间:2026-06-24 14:52:07

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。