user3020233
user3020233

Reputation: 327

Please help me understand Boost::Any

Boost::Any uses a generalized base class placehoder from which derive the templated holder class. placehoder offers an interface with virtual methods, notably a method to retrieve the typeid of what the any contains. The any then contains a pointer to a placeholder. What I don't understand is the purpose of placeholder and the use of virtual methods. Let this simplified construct of any (for which the interface's source is available here) :

class any
{
public:
    template<typename ValueType>
    any(const ValueType & value) : content(new holder<ValueType>>(value)) {}

private:
    class placeholder
    {
    public:
        virtual const std::type_info & type_info() const = 0;
    };

    template<typename ValueType>
    class holder : public placeholder
    {
    public:
        holder(const ValueType &value) : held(value) {};
        virtual const std::type_info &type_info() const
        {
            return typeid(ValueType);
        }
        const value_type held;
    };

    placeholder *content;
}

It looks to me like placeholder could completly be removed and placeholder *content; substituted with holder *content;.

Moreover, I don't understand the mechanism of assignment used in any. Let :

any & operator=(any rhs)
{
    any(rhs).swap(*this);
    return *this;
}

Which asigns an any to another. This will construct a temporary any with rhs's content and swap it with the current object, effectively doing what we want but... What becomes the point of all of this if any just systematically constructs a new, temporary any and affect it to the current object for all assignment operations?

Upvotes: 2

Views: 162

Answers (1)

Michael Anderson
Michael Anderson

Reputation: 73490

It looks to me like placeholder could completely be removed and placeholder *content; substituted with holder *content;.

Nope, since holder is a templated class this is invalid:

holder * content

You need to write

holder<T> * content

but you dont know T - (which is the whole point of boost::any). So instead you create a common base class for all the holder<T> classes - which is what placeholder is.

Moreover, I don't understand the mechanism of assignment used in any. Let :

any & operator=(any rhs)
{
    any(rhs).swap(*this);
    return *this;
}

This is the commonly known "copy and swap" idiom. Consider what a more standard implementation would look like:

any & operator=(const any &rhs)
{
    //Watch out for self-assignment.
    if(&any==this) return *this;

    //Clean out the old data
    delete content;

    // Update our content
    content = rhs.content->clone();

    return *this;
}

This duplicates a lot of behaviour in the copy constructor. The copy and swap idiom is a way to remove that duplication. The copying is done by the copy-constructor and the cleanup is done by the temporary destructor.

I do think its odd that the operator= gets a copy as its argument since it's not accepting a const reference, and then creates a second copy from that one. I would have expected either:

any & operator=(const any & rhs)
{
    any(rhs).swap(*this);
    return *this;
}

or

any & operator=(any rhs)
{
    rhs.swap(*this);
    return *this;
}

Upvotes: 5

Related Questions