Open In App

std::any Class in C++

any is one of the newest features of C++17 that provides a type-safe container to store single value of any type. In layman’s terms, it is a container which allows one to store any value in it without worrying about the type safety. It acts as an extension to C++ by mimicking behaviour similar to an object type in .NET/Java or void* type in C language . It has been designed based on boost::any and is available in “any” header file.

Syntax:



any var= value/object; 

where value is something like “17” or “Hello World”

Initialisation of any:

any can be constructed in three different ways using:



  1. Copy Initialization

    Syntax:

    any variable_name = object/value;
    
  2. Parameterized constructor / brace initializer.

    Syntax:

    any variable_name ( object/value);
    
  3. Using the assignment operator

    Syntax:

    any variable_name;
    variable_name= object/value;
    
  4. Converting any_var value into its original type:

    One must use any_cast<type>( any_var ) to convert any_var value into its original type. If a stored value has a type other than the one trying to cast to, then a “bad_any_cast” exception will be thrown by the compiler.

    Note: The type during the cast must exactly be same as the original type. There is no automatic promotion or demotion during the cast. Hence special care must be taken while casting the value to its original type.

    A Simple Example ( Illustrates the construction / reading values of any)




    #include <any>
    #include <iostream>
    #include <string>
    using namespace std;
      
    int main()
    {
        try {
      
            // Integer 42:  Using the copy initialisation
            any value = 42;
            cout << "\n Value: "
                 << any_cast<int>(value);
      
            // Using the assignment operator
            // to store a string
            value = "Hello World";
            cout << "\n Value: "
                 << any_cast<const char*>(value);
      
            // Using the parametrized constructor
            any val(19.0);
            cout << " \n Value: "
                 << any_cast<double>(val);
      
            any val_brace{ string("Brace Initialisation") };
            cout << " \n Value: "
                 << any_cast<string>(val_brace);
        }
      
        catch (bad_any_cast& e) {
            cout << "\n"
                 << e.what();
        }
        return 0;
    }
    
    

    Output:

     Value: 42 
     Value: Hello World 
     Value: 19 
     Value: Brace Initialisation
    

    Member functions:

    1. emplace : Changes the contained object, constructing the new object directly
    2. reset : Destroys the contained object ( Calls the destructor of the object)
    3. has_value : Checks if the “any_variable” holds a value within it
    4. type : Returns the type id of the contained value

    Lets see the methods one by one in detail:

Uses of any

Typical uses include

  1. In Libraries, When a library type has to hold or pass anything without knowing the set of available types.
  2. Message Passing
  3. Implementing Parser Libraries for ex. JSON parser
  4. User Interface: controls might hold anything
  5. Entity component system.

One of the main benefits of any is its viable substitution with void*. void* has limited capability( Only stores pointer types) and is considered as an unsafe pattern.

Error Handling:

There are two options regarding error handling for any class:

  1. Using Exceptions: bad_any_cast is the exception thrown by the value-returning forms of any_cast on type-mismatch.

    Example:




    // C++ program to demonstrate
    // using exceptions of any class
      
    #include <any>
    #include <iostream>
    #include <string>
      
    int main()
    {
        try {
            any var = 12.0f;
      
            cout << " \n Value:  "
                 << any_cast<double>(var);
        }
      
        catch (bad_any_cast& e) {
            cout << "\n"
                 << e.what();
        }
        return 0;
    }
    
    

    Output

    Value:  
    bad any_cast
    
  2. Returning a Pointer: Returning a pointer is useful when the exception mechanism has been disabled in the compiler. This particular overload of any_cast returns the pointer to the contained object if the cast was successful and returns nullptr.

    Example:




    // C++ program to demonstrate
    // returning pointer of any class
      
    #include <any>
    #include <iostream>
    #include <string>
    using namespace std;
      
    int main()
    {
        any var = 12.0f;
      
        // Special Overload of any_cast
        auto* tval = any_cast<float>(&var);
        if (!tval) {
      
            // Type-mismatch
            cout << " \n Bad_any_cast ";
        }
        else {
      
            // Value of the object
            cout << " \n Value:  "
                 << *tval;
        }
      
        return 0;
    }
    
    

    Output:

    Value:  12
    

Memory Considerations

Although any gives a lot of flexibility with the language, the main issue with any is extra dynamic memory allocations. As the container is not aware of object contained dynamic allocation becomes a must for any.

But according to the standard, Implementations should avoid the use of dynamically allocated memory for a small contained value. Example: where the object constructed is holding only an int. Such small-object optimisation shall only be applied to types T for which is_nothrow_move_constructible_v true.

What this typically means is that the compiler must use small buffer optimization ( SBO) in which a certain amount of memory has to be reserved for the type to be contained.

From the table above, one can see that reserved memory for SBO in some cases could go upto 64 bytes! ( MSVC-64 bit). This means that each object of any would require 64 bytes of memory reserved even if the object is small which is a considerable memory overhead.

Although any is a very powerful feature in C++. It comes with a considerable amount of overhead in terms of memory.


Article Tags :