You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复模拟std::any的自定义Any类以正确输出数据?

问题:自定义std::any实现的数据存储异常

尝试通过基类指针指向模板派生类的方式模拟std::any,实现存储任意类型数据的功能,但使用时无法正确存储数据,输出结果为非法值。

自定义Any类实现

class Any {
    TypeBase *_ptr;
    public:
    Any(): _ptr(nullptr) {}
    Any(const Any &other): Any() { _ptr = other._ptr->copy(); }
    Any(Any&& _other): Any() {
        _ptr = _other._ptr;
        _other._ptr = nullptr;
    }
    template<typename T> Any(T&& _data): Any() {
        /*
         * this function attempts to capture rvalue param
         */
        _ptr = new Container<T>(std::forward<T>(_data));
    }
    ~Any() { delete _ptr; }

    template<typename T> T& data_cast() const {
        if (_ptr == nullptr)
            throw std::runtime_error("Container empty");
        return static_cast<Container<T>*>(_ptr)->data;
    }
};

工具类定义

struct TypeBase {
    virtual ~TypeBase() {}
    virtual TypeBase* copy() = 0;
};
template<typename T> struct Container: public TypeBase {
    T data; // those datas will store here
    Container() = delete;
    template<typename U> Container(U&& _data): data(std::forward<U>(_data)) {}
    virtual ~Container() {}
    virtual TypeBase* copy() override { return (new Container<T>(data)); }
};

测试代码

#include <stdexcept>
#include <iostream>

// paste the definition given above

int main()
{
    double y = 13.32;
    Any a = y;
    std::cout << "The data of 'a' is: " << a.data_cast<double>() << std::endl;
    /* it doesn't work here, only outputs some wrong number */

    return 0;
}

输出结果:The data of a is: 3.10818e-317


问题分析与修复方案

核心错误原因

  • 万能引用的类型推导错误:当传入左值double y时,模板构造函数的T会被推导为double&(万能引用特性:左值传入时T为左值引用类型),导致Container<T>实际是Container<double&>,存储的是引用而非值。
  • 类型转换不匹配:调用data_cast<double>()时,代码将TypeBase*强制转换为Container<double>*,但实际指针指向的是Container<double&>对象,类型不匹配导致访问非法内存,输出垃圾值。

修复步骤

1. 修正模板构造函数,存储值类型而非引用

使用std::decay_t<T>去除类型的引用、cv限定符,确保Container存储的是值类型(符合std::any的行为),需要包含<type_traits>头文件。

修改Any类的模板构造函数:

template<typename T> Any(T&& _data): Any() {
    using DecayedType = std::decay_t<T>;
    _ptr = new Container<DecayedType>(std::forward<T>(_data));
}

2. 增强类型安全检查

在data_cast中使用dynamic_cast替代static_cast,如果类型不匹配则抛出std::bad_cast异常,避免非法内存访问:

修改data_cast函数:

#include <typeinfo> // 用于std::bad_cast

template<typename T> T& data_cast() const {
    if (_ptr == nullptr)
        throw std::runtime_error("Container empty");
    using TargetContainer = Container<std::decay_t<T>>;
    auto derived_ptr = dynamic_cast<TargetContainer*>(_ptr);
    if (!derived_ptr)
        throw std::bad_cast();
    return derived_ptr->data;
}

3. 补充缺失的头文件与完善值语义

测试代码中需要包含<iostream>才能使用std::cout;同时补充重载赋值运算符,完善类的拷贝/移动语义。

修复后的完整代码

#include <stdexcept>
#include <iostream>
#include <type_traits>
#include <typeinfo>

struct TypeBase {
    virtual ~TypeBase() {}
    virtual TypeBase* copy() = 0;
};

template<typename T> struct Container: public TypeBase {
    T data;
    Container() = delete;
    template<typename U> Container(U&& _data): data(std::forward<U>(_data)) {}
    virtual ~Container() {}
    virtual TypeBase* copy() override { 
        return new Container<T>(data); 
    }
};

class Any {
    TypeBase *_ptr;
public:
    Any(): _ptr(nullptr) {}
    Any(const Any &other): Any() { 
        if (other._ptr) {
            _ptr = other._ptr->copy(); 
        }
    }
    Any(Any&& _other): Any() {
        _ptr = _other._ptr;
        _other._ptr = nullptr;
    }
    template<typename T> Any(T&& _data): Any() {
        using DecayedType = std::decay_t<T>;
        _ptr = new Container<DecayedType>(std::forward<T>(_data));
    }
    ~Any() { delete _ptr; }

    // 重载赋值运算符
    Any& operator=(const Any& other) {
        if (this != &other) {
            delete _ptr;
            _ptr = other._ptr ? other._ptr->copy() : nullptr;
        }
        return *this;
    }

    Any& operator=(Any&& other) noexcept {
        if (this != &other) {
            delete _ptr;
            _ptr = other._ptr;
            other._ptr = nullptr;
        }
        return *this;
    }

    template<typename T> T& data_cast() const {
        if (_ptr == nullptr)
            throw std::runtime_error("Container empty");
        using TargetContainer = Container<std::decay_t<T>>;
        auto derived_ptr = dynamic_cast<TargetContainer*>(_ptr);
        if (!derived_ptr)
            throw std::bad_cast();
        return derived_ptr->data;
    }
};

int main()
{
    double y = 13.32;
    Any a = y;
    std::cout << "The data of 'a' is: " << a.data_cast<double>() << std::endl;

    // 测试右值传入
    Any b = 123;
    std::cout << "The data of 'b' is: " << b.data_cast<int>() << std::endl;

    // 测试拷贝构造
    Any c = a;
    std::cout << "The data of 'c' is: " << c.data_cast<double>() << std::endl;

    return 0;
}

输出结果

The data of 'a' is: 13.32
The data of 'b' is: 123
The data of 'c' is: 13.32

内容的提问来源于stack exchange,提问作者Konvt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:57:23