The different styles of getting the stored value differ not only in semantics, but also how they return the stored value.. If you pass a pointer argument, you get a pointer to the stored
Trang 1std::sort(properties.begin(),properties.end());
std::for_each(
properties.begin(),
properties.end(),
print_names);
std::cout << "\n";
std::cout <<
boost::any_cast<std::string>(properties[0].value()) << "\n";
std::cout <<
boost::any_cast<int>(properties[1].value()) << "\n";
std::cout <<
boost::any_cast<double>(properties[2].value()) << "\n";
}
Notice that we didn't have to explicitly create the anys needed for property's constructor That's because any's converting constructor isn't explicit Although constructors taking one argument should typically be declared explicit, any is an exception to the rule Running the program gives us this output
Example of using any for storing properties
A
B
C
Thirty something
30
3.1415
In this example, because the container was sorted, we retrieved the properties by index, and as we knew their respective types beforehand, we didn't need a
try/catch block for the retrieval When retrieving the value of an instance of any, pass the any by const reference to any_cast if a failure indicates a real error
std::string s=boost::any_cast<std::string>(a);
When a failure is not necessarily an error, pass the any by pointer
std::string* ps=boost::any_cast<std::string>(&a);
Trang 2The different styles of getting the stored value differ not only in semantics, but also how they return the stored value If you pass a pointer argument, you get a pointer
to the stored value; if you pass a const reference argument, you get a copy of the value
If the value type is expensive to copy, pass the any by pointer to avoid copying the value
There's More to any
There are a few more member functions provided by any, such as testing whether
an instance of any is empty or not, and swapping the values of two instances of any The following example shows how to use them
#include <iostream>
#include <string>
#include "boost/any.hpp"
int main() {
std::cout << "Example of using any member functions\n\n";
boost::any a1(100);
boost::any a2(std::string("200"));
boost::any a3;
std::cout << "a3 is ";
if (!a3.empty()) {
std::cout << "not ";
}
std::cout << "empty\n";
a1.swap(a2);
try {
std::string s=boost::any_cast<std::string>(a1);
std::cout << "a1 contains a string: " << s << "\n";
}
catch(boost::bad_any_cast& e) {
std::cout << "I guess a1 doesn't contain a string!\n";
}
if (int* p=boost::any_cast<int>(&a2)) {
std::cout << "a2 seems to have swapped contents with a1: "
<< *p << "\n";
}
else {
Trang 3std::cout << "Nope, no int in a2\n";
}
if (typeid(int)==a2.type()) {
std::cout << "a2's type_info equals the type_info of int\n";
}
}
Here's the output from running the program
Example of using any member functions
a3 is empty
a1 contains a string: 200
a2 seems to have swapped contents with a1: 100
a2's type_info equals the type_info of int
Let's examine that code more closely To test whether an instance of any contains
a value, we called the member function empty We tested the any a3 like this
std::cout << "a3 is ";
if (!a3.empty()) {
std::cout << "not ";
}
std::cout << "empty\n";
Because we default constructed a3, a3.empty() returns TRue The next thing
is to swap the contents of a1 with a2 You may wonder why you'd want to swap their contents One plausible scenario is when the identities of the any instances are important (swap only exchanges the contained values) Another reason is to avoid copying when you don't need to keep the original value
a1.swap(a2);
Finally, we use the member function type, which returns a const
std::type_ info&, to test if the contained value is of the type int
if (typeid(int)==a2.type()) {
Note that if an any stores a pointer type, that is reflected in the returned
std::type_info
Trang 4Storing Pointers in any
Often, the test for empty is enough to know whether the object really contains something valid However, if an any might hold a pointer, be extra careful to test the pointer before trying to dereference it Simply testing whether the any is
empty is not enough, because an any is not considered to be empty when it holds a pointer, even if that pointer is null
boost::any a(static_cast<std::string*>(0));
if (!a.empty()) {
try {
std::string* p=boost::any_cast<std::string*>(a);
if (p) {
std::cout << *p;
}
else {
std::cout << "The any contained a null pointer!\n";
}
}
catch(boost::bad_any_cast&) {}
}
A Better WayUsing shared_ptr
Another complication when storing raw pointers in any is the destruction
semantics The any class accepts ownership of the value it stores, because it keeps
an internal copy of the value, which is destroyed together with the any However, destroying a raw pointer doesn't invoke delete or delete[] on it! It only reclaims the memory occupied by the pointer This makes storing a raw pointer in any problematic, so it's a good idea to use smart pointers instead Indeed, using smart pointers (see "Library 1: Smart_ptr 1") is an ideal way to store a pointer to data in an any This solves the problem of making sure that the memory
associated with a contained pointer is properly deleted When the smart pointer is destroyed, it takes appropriate action to ensure the memory and any data in it are properly destroyed By contrast, note that std::auto_ptr is not appropriate This is because auto_ptr doesn't have normal copy semantics; accessing the value in an any would transfer ownership of the memory and any data in it from the any to the returned auto_ptr
Trang 5Consider the following code
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include "boost/any.hpp"
#include "boost/shared_ptr.hpp"
First, we'll define two classes, A and B, each with operations is_virtual, which
is virtual, and not_virtual, which is not virtual (had it been virtual, the name would be an extremely bad choice) We want to store objects of these types in anys
class A {
public:
virtual ~A() {
std::cout << "A::~A()\n";
}
void not_virtual() {
std::cout << "A::not_virtual()\n";
}
virtual void is_virtual () {
std::cout << "A:: is_virtual ()\n";
}
};
class B : public A {
public:
void not_virtual() {
std::cout << "B::not_virtual()\n";
}
virtual void is_virtual () {
std::cout << "B:: is_virtual ()\n";
}
};
Let's now define a free function, foo, which accepts an argument that is a
reference to any and that examines the any using any_casts to the types that the function knows how to handle If there's no match, the function simply ignores the any and returns It tests for the types shared_ptr<A> and
Trang 6shared_ptr<B>, respectively, and calls is_virtual (the virtual function) and not_virtual on them
void foo(boost::any& a) {
std::cout << "\n";
// Try boost::shared_ptr<A>
try {
boost::shared_ptr<A> ptr=
boost::any_cast<boost::shared_ptr<A> >(a);