Boost.any for any type of storage

Source: Internet
Author: User

when you need a variable type, there are three possible solutions:
    1. Unlimited types, such as void*. This method cannot be type-safe and should be avoided as a disaster.
    2. Variable types, which are types that support multiple types of storage and fetching.
    3. Types that support conversions, such as conversions between string types and integer types.
Any implements the second scenario, a variable-value-based type with infinite possible types. This library is often used to store different types of things in a container in a standard library.

how the Any library improves your program
Type-safe storage of any type and secure retrieval
Storing different types of methods in a standard reservoir
The type can be routed without knowing the type

The Any library provides a type, any, which allows to be stored in any type and retrieved later without loss of type safety. It's kind of like a mutable type of compound: It can hold any type, but you have to know the type to retrieve the value. There are times when you want to deposit unrelated types in the same container. There are times when some code just wants to transfer data from one pointer to another, not the type of the data. On the surface, these things can be done easily. They can be implemented through a class-free type, such as void*. They can also be implemented by using a union that contains different types. There are many mutable types that are implemented through some type identification mechanisms. Unfortunately, all of this lacks type safety, and we should deliberately bypass the type system only in the most manageable cases. The containers of the standard library are specific to the types they contain, which means that it is not possible to deposit different types of elements within a container. Fortunately, the solution is not necessarily void* because the any library allows you to store different types and retrieve them later. There is no way to retrieve the stored value without knowing the actual type, which is guaranteed by type safety.

When designing a framework, it is not possible to know in advance which types to use with the framework class. A common approach is to require the user of the framework to adhere to an interface or derive from a base class provided by the framework. This is justified because the framework may need to communicate with different advanced classes to be used. However, there is a situation where the framework does not (or cannot) know any relevant information about the type of deposit or acceptance. Do not bypass the type system to use the Void* method, the framework can use any.

How any applies to the standard library
An important feature of any is that it provides the ability to store different types of objects into a standard storage device. It is also a mutable data type, which is very much needed and lacking in the C + + standard library.
Boost.anyClass any allows type-safe storage and retrieval of any type. Unlike an untyped type, any saves the type information and does not let you get the value that was deposited without knowing the correct type. Of course, there is a way for you to ask about the type of information, as well as the method of testing the saved values, but ultimately, the caller must know the true type of the value in the any object, otherwise they cannot access any. Any can be viewed as a security for lockout. You can't get into it without the right key. Any has the following requirements for the type it holds:
    1. Copyconstructible it must be able to replicate this type
    2. Non-throwing destructor Just like all destructors should!
    3. Assignable to ensure strong exception security (types that do not conform to the assignable requirements can also be used for any, but there is no guarantee of strong exception security)
Namespace Boost {  class any {public  : any    ();    Any (const any&);    Template<typename valuetype> any     (const valuetype&);    ~any ();    any& swap (any &);    any& operator= (const any&);    Template<typename valuetype>     any& operator= (const valuetype&);    BOOL empty () const;    Const std::type_info& type () const;  };}

member functions
any (); The default constructor creates an empty any instance, which is an any that does not contain a value. Of course, you cannot retrieve the value from an empty any, because no value exists.
Any (const any& other); Creates a separate copy of an existing any object. The value contained in other is copied and stored in this.
Template<typename valuetype> any (const valuetype&); This template constructor is stored as a copy of an incoming ValueType type parameter. The parameter is a const reference, so it is legal to pass in a temporary object to deposit any. Note that the constructor is not explicit, and if so, any is difficult to use and does not add security.
~any (); The destructor destroys the contained value, but note that since the destruction of a bare pointer does not call operator delete or operator delete[], when using the pointer in any, you should wrap the bare pointer into an image shared_ptr Smart pointers like that.
any& Swap (any& other); The interchange has a value in two any objects.
any& operator= (const any& Other), if the any instance is not empty, discards the stored value and stores a copy of the other value.
Template<typename valuetype> any& operator= (const valuetype& value), if the any instance is not empty, discards the stored value and deposits it in a copy of value. Value can be any type that conforms to any requirement.
BOOL Empty () const, given whether the any instance currently has a value, regardless of the value. Thus, when any holds a pointer, empty also returns false, even if the pointer value is NULL.
Const std::type_info& type () const; gives the types of stored values. If any is empty, the type is void.
Common Functions
Template<typename valuetype> ValueType any_cast (const any& operand); Any_cast gives you access to the values stored in any. parameter is the any object that needs to retrieve the value. If the type ValueType does not match the stored value, any throws a Bad_any_cast exception. Please note that this syntax is a bit like dynamic_cast.
Template<typename valuetype> Const valuetype* any_cast (const any* operand); an overload of any_cast that accepts a pointer to any and returns a pointer to the stored value. If the type in any is not ValueType, a null pointer is returned. Please note again that this syntax is a bit like dynamic_cast.
Template<typename valuetype> valuetype* any_cast (any* operand); another overload of Any_cast, similar to the previous version, but the previous version uses the const pointer parameter and returns Const pointer, this version is not.
ExceptionBad_any_cast

This exception is thrown when you attempt to convert an any object to a type other than the one stored by the object. Bad_any_cast derived from Std::bad_cast. Attentionwhen calling Any_cast with pointer arguments, no exception is thrown(similar to returning a null pointer when using dynamic_cast on a pointer), whereas using dynamic_cast on a reference type throws an exception on failure.
usageThe any library is defined within the namespace boost. You will use the class any to save the value, using the template function Any_cast to retrieve the stored value. In order to use any, include the header file "Boost/any.hpp". It would be wise to only allow you to access its value if you know the type. For this library, you typically only need to remember two things: class any, for storing values, and for template function Any_cast, for retrieving values.when a transformation failure is not an error, use the pointer to pass any, but if the transformation failure is an error, you should use a const reference to pass it, which allows Any_cast to throw an exception on failure. If you pass a pointer parameter, you get a pointer to the saved value, and if you pass a const reference parameter, you get a copy of the saved value. If the value type is expensive at the time of copying, you should pass the pointer to avoid a copy of the value. Using any allows you to use them where the standard library containers and algorithms are not available, allowing you to write code that is more maintainable and easier to understand.
#include <iostream> #include <string> #include <utility> #include <vector> #include <boost/ any.hpp>using namespace std;struct a{void Some_function () {cout << a::some_function () << Endl;} };struct b{void Some_function () {cout << "b::some_function ()" << Endl;}}; struct c{void Some_function () {cout << "c::some_function ()" << Endl;}}; void Print_any (boost::any& a) {if (A * pa=boost::any_cast<a> (&a)) {Pa->some_        function ();        } else if (b* pb=boost::any_cast<b> (&a)) {pb->some_function ();        } else if (c* pc=boost::any_cast<c> (&a)) {pc->some_function (); } else {try {cout << boost::any_cast<string&                gt; (a) << Endl; } catch (Boost::bad_any_cast &e)                {cout << "oops~" << e.what () << Endl;        }}}int Main () {std::vector<boost::any> store_anything;        Store_anything.push_back (A ());        Store_anything.push_back (B ());        Store_anything.push_back (C ());        Store_anything.push_back (String ("This is fantastic!"));        Store_anything.push_back (3);        Store_anything.push_back (Make_pair (True, 7.92)); For_each (Store_anything.begin (), Store_anything.end (), print_any);}

Execution Result: a::some_function ()
B::some_function ()
C::some_function ()
This is fantastic!
oops~boost::bad_any_cast:failed conversion using Boost::any_cast
oops~boost::bad_any_cast:failed conversion using Boost::any_cast
member functions use
#include <iostream> #include <string> #include <boost/any.hpp>using namespace Std;int main () {boost        :: Any A1 (100);        Boost::any A2 (std::string ("200"));        Boost::any A3; cout << "A3 is" << (A3.empty ()? "        Empty ":" Not Empty ") << Endl;        A1.swap (A2);                try {string s=boost::any_cast<std::string> (A1);        cout << "A1 contains a string:" << s << endl; } catch (boost::bad_any_cast& e) {std::cout << "A1 doesn ' t contain a string!" <        < E.what () << Endl; } if (int* p=boost::any_cast<int> (&AMP;A2)) {cout << "A2 seems to has swapped C        Ontents with A1: "<< *p << Endl;        } else {cout << "Nope, no int in A2" << Endl; } if (typeid (int) ==a2.type ()) {cout << A2 ' s type_inFo equals the type_info of int "<< Endl; }}

Execution result: A3 is empty
A1 contains a string:200
A2 seems to has swapped contents with a1:100
A2 ' s type_info equals the type_info of int
Save PointerOften, testing empty is enough to know if an object really contains something valid. However, if any is holding a pointer, you should test the pointer with extra care before you dereference it. It is not enough to simply test if any is empty, because an any is considered non-null when holding a pointer, even if the pointer is empty.
Another trouble with saving a bare pointer in any is the semantics of the destructor. The any class accepts ownership of its stored value because it maintains an internal copy of the value and destroys it with any. However, destroying a bare pointer does not call it delete or delete[]! It simply requires the return of the point of memory that belongs to the pointer. This makes it problematic to save pointers in any, so a better approach is to use smart pointers instead. Indeed, using smart pointers is a good way to save pointers in an any. It solves the problem of ensuring that the memory pointed to by the stored pointer is properly freed. When the smart pointer is destroyed, it correctly ensures that the memory and the data in it are destroyed correctly. As a comparison, be aware that std::auto_ptr is not a suitable smart pointer. This is because AUTO_PTR does not have the usual copy semantics; accessing the value in an any will transfer the ownership of the memory and its data from any to the returned auto_ptr.
#include <iostream> #include <string> #include <algorithm> #include <vector> #include <boost         /any.hpp> #include <boost/shared_ptr.hpp>using namespace Std;class a{private:string m_str;  Public:a (String str): M_str (str) {} virtual ~a () {cout << a::~a ()---<< M_str << Endl;                } void Not_virtual () {cout << "a::not_virtual ()---" << m_str << Endl;} virtual void is_virtual () {cout << "A:: Is_virtual ()---" << m_str<< Endl;}};        Class B:public a{private:string m_str; Public:b (String str): A (str), M_STR (str) {} ~b () {cout << b::~b ()---<< m_str &lt                ;< Endl;}                void Not_virtual () {cout << "b::not_virtual ()---" << m_str << Endl;} virtual void is_virtual () {cout << "B:: Is_virtual ()---" << m_str << Endl;}}; void foo (boost::any& a) {try {boost::shared_ptr<a> ptr = boost::any_cast<boost:                :shared_ptr<a> > (A);                Ptr-> is_virtual ();                Ptr->not_virtual ();        Return } catch (boost::bad_any_cast& e) {} try {boost::shared_ptr<b> ptr = boost::a                Ny_cast<boost::shared_ptr<b> > (a);                Ptr-> is_virtual ();                Ptr->not_virtual ();        Return } catch (boost::bad_any_cast& e) {} cout << "~~~~~~~other types~~~~~~~~" << Endl;}        int main () {Boost::any A1 (boost::shared_ptr<a> (New A ("A1"));        Boost::any A2 (String ("Just a String"));                {Boost::any B1 (boost::shared_ptr<a> (New B ("B1"));                Boost::any B2 (boost::shared_ptr<b> (New B ("B2")));                Vector<boost::any> VEC; Vec.pUsh_back (A1);                Vec.push_back (A2);                Vec.push_back (B1);                Vec.push_back (B2);                For_each (Vec.begin (), Vec.end (), foo);        cout << Endl; }}

Execution Result: A:: Is_virtual ()---A1
A::not_virtual ()---A1
~~~~~~~other types~~~~~~~~
B:: Is_virtual ()---B1
A::not_virtual ()---B1
B:: Is_virtual ()---B2
B::not_virtual ()---B2

B::~b ()---B2
A::~a ()---B2
B::~B ()---B1
A::~a ()---B1
A::~a ()---any that contains a string in the A1 vector. This shows that it is possible and often reasonable to save some types of unknown types to a function that are to be called later, and are usually justified; These functions only need to handle the types they need to manipulate!
The third element contains a shared_ptr<a> that points to the B instance. This example shows how any can be as polymorphic as other types. Of course, if we use a bare pointer, we need to use static_cast to save the pointer to the type we want to identify. Note that the function a::not_virtual is called instead of b::not_virtual. The reason is that the static type of the pointer is a *, not a b*.
At the end of that scope, the vector is destroyed, and it destroys the contained any instance, which then destroys all the shared_ptr and correctly sets the reference parameter to zero. Next, our hands are safely and effortlessly destroyed!

This example shows something more important than how to use a smart pointer with any, and it shows that the type of any is either simple or complex and irrelevant.if the cost of copying the stored value is staggering, or if you need to share usage and control lifetimes, you should consider using smart pointers, just like storing values in a container using the standard library. The same reasoning applies to any, which is usually consistent with the two principles, just as using any in a container means saving different types.

SummaryThis type can contain different types of values, and is very different from the non-class type (such as void*). We are always heavily reliant on type safety in C + +, and only in rare cases will we be willing to work without it. There are good reasons for this: type safety prevents us from making mistakes and improves the performance of our code. Therefore, we should avoid the non-class type. Also, it is rare to find that you need heterogeneous storage, or to isolate users to the details of a type, or to gain extreme flexibility at a lower level. Any provides these features while maintaining type safety, which is the best extension of our toolkit!

Use any library in the following situations:
    1. You need to store different types of values in the container.
    2. Need to save unknown type
    3. Type is passed to a level that does not need to know anything about that type of information
The design of any is also a valuable lesson on how to encapsulate a type without affecting the type of envelope class. This design can be used to create generic function objects, generic iterators, and so on. It is an example of demonstrating the power of encapsulation and the polymorphism associated with templates.

In the standard library, there are good tools for storing multiple elements. When you need to store heterogeneous elements, we want to avoid using the new collection type. Any provides a method that, in most cases, can be used with existing containers. To some extent, the template class any expands the capacity of the standard reservoir, putting different types into a wrapper of the same type, which can be placed in the aforementioned container. It's easy to add boost.any to the existing code. It does not need to modify the design and immediately adds flexibility. The interface is very small, which makes it a very easy tool to understand.

Boost.any for any type of storage

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.