TTL::变体,放置新

ttl::variant, placement new

本文关键字:变体 TTL      更新时间:2023-10-16

我使用的是"小模板库"中的变体类型。变体定义为:

template< TTL_TPARAMS_DEF(TTL_MAX_TYPELIST_PARAMS, empty_type) >
struct variant
{
    typedef variant this_t;
    typedef meta::typelist< TTL_ARGS(TTL_MAX_TYPELIST_PARAMS) > list;
    ...
    template< typename T >
    variant( const T& r ) : which_(0), pnt_(0)
    {
        typedef meta::find_equivalent_type<const T&, list> found;
        pnt_ = new(stor_.buf_) ttl::data_holder<typename found::type>(r);
        which_ = found::index;
    }
    ...
private:
    template<int N> 
    struct storage
    {
        union
        {
            ttl::data_holder_base dummy;  //hope to satisfy alignment settings
            char buf_[N];
        };
    };
    int which_;
    ttl::data_holder_base* pnt_;
    storage< sizeof(ttl::data_holder<typename list::largest_type>) > stor_;
    ....
};

struct data_holder_base {};
template< typename T >
struct data_holder : data_holder_base
{
    ...
    typedef const T& param_type;
    T d;
    ...
    data_holder( param_type d_ ) : d(d_) {}
    ...
};

当我通过网络发送这种类型的对象并使用"memcpy"重建"它时,很明显指针"pnt_"将指向涅槃。由于我知道存储的类型,我尝试使用强制转换重建指针"pnt_":

template<typename T>
inline void rebuild()
{
    pnt_ = reinterpret_cast<ttl::data_holder<T>*>(stor_.buf_); 
}

对于我检查此示例的情况,它有效。但我不知道放置新(pnt_ = new(stor_.buf_) ...(如何将对象放入stor_.buf_中。是否需要存储类似std::distance(&stor_.buf_[0], pnt_)的东西才能找到对象?

还是有没有其他方法可以让pnt_回来?

谢谢 马里奥

放置

new将新对象放在stor_.buf_中,因为这就是放置new的定义方式。你给new你希望它使用的内存的地址,它会在该位置构造对象。它返回完全相同的地址,因此存储在pnt_中的地址是stor_.buf_的地址,但构造对象的类型是ttl::data_holder<found::type>,而不是char*。由于地址相同,因此您提到的std::distance值将始终为零(假设调用甚至可以编译,但不会编译,因为参数类型不同(。

stor_.buf_的地址也将始终等于stor_.dummy的地址。您可以通过分配如下pnt_来简化添加的代码:

pnt_ = &stor_.dummy;

但是,由于您显然只是在套接字上复制了原始内存,因此修复此variant对象的内部只是冰山一角。您的变体包含的值也可能包含地址,您无法进入该地址。即使您这样做,您需要的地址也可能不可用。您很幸运variant您正在修复的地址恰好是同一对象中的地址,因此很容易计算。但是考虑 std::string ,它从免费存储中分配内存;通过套接字发送一个不会给你任何可用的东西在另一端 - 它甚至可能根本不给你字符数据。相反,您应该采用其他一些技术来序列化和反序列化ttl::variant对象。您可以在Stack Overflow上发布一个问题,询问如何做到这一点。