0

我正在使用"Tiny Template Library"中的变体类型。变体定义为:

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_”将指向 Nirvana。由于我知道存储的类型,我尝试使用强制转换重建指针“pnt_”:

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

对于我检查了这个例子的情况,它可以工作。但我不知道放置 new( pnt_ = new(stor_.buf_) ...) 是如何将对象放入stor_.buf_. 是否需要存储诸如std::distance(&stor_.buf_[0], pnt_)查找对象之类的内容?

或者有什么不同的方法可以pnt_返回?

谢谢马里奥

4

1 回答 1

0

Placement new puts the new object in stor_.buf_ because that's how placement new is defined to work. You give new the address of the memory you want it to use, and it constructs the object in that location. It returns the very same address, so the address stored in pnt_ is that of stor_.buf_, but with the type of the constructed object, ttl::data_holder<found::type>, instead of char*. Since the addresses are the same, the std::distance value you mention would always be zero (assuming the call would even compile, which it won't because the argument types are different).

The address of stor_.buf_ will also always be equal to that of stor_.dummy. You could make your added code simpler by assigning pnt_ like this:

pnt_ = &stor_.dummy;

However, since you've apparently just copied raw memory over the socket, fixing up the internals of this variant object is only the tip of the iceberg. The value that your variant holds might also contain addresses, and you have no way of reaching inside that. Even if you do, the address you need might not be available. You were lucky with variant that the address you're fixing happens to be an address within the same object, so it's easy to compute. But consider std::string, which allocates memory from the free store; sending one over a socket won't give you anything usable on the other end — it might not even give you the character data at all. You should instead pursue some other technique for serializing and deserializing ttl::variant objects. You could post a question on Stack Overflow asking how to do it.

于 2012-05-22T18:54:12.617 回答