Reputation: 327
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
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