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)

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    #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;
    }

    chevron_right

    
    

    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:

    • emplace: emplace member function is similar to the assignment operator and is used to change the contained object with a new object.

      Program:

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

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

      chevron_right

      
      

      Output:

      Value:  4.2 
      Value:  44
      
    • reset: It destroys the contained object by calling the destructor of the contained object.

      Program:



      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      // C++ program to demonstrate
      // reset() method of any class
        
      #include <any>
      #include <iostream>
      #include <string>
        
      int main()
      {
          try {
              any var = 4.2;
              cout << " \n Value:  "
                   << any_cast<double>(var);
        
              var.reset();
              if (!var.has_value())
                  cout << " \n No value found in var variable";
          }
          catch (bad_any_cast& e) {
              cout << "\n"
                   << e.what();
          }
          return 0;
      }

      chevron_right

      
      

      Output:

      Value:  4.2 
      No value found in var variable
      
    • has_value: This member function is used to check whether the object contains a value or not

      Program:

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      // C++ program to demonstrate
      // has_value() method of any class
        
      #include <any>
      #include <iostream>
      #include <string>
        
      int main()
      {
          try {
              any var = 9.5;
              cout << " \n Value:  "
                   << any_cast<double>(var);
        
              if (var.has_value())
                  cout << " \n Value found of type "
                       << var.type().name();
          }
        
          catch (bad_any_cast& e) {
              cout << "\n"
                   << e.what();
          }
          return 0;
      }

      chevron_right

      
      

      Output:

       Value:  9.5 
       Value found of type d
      
    • type: This member function returns a type_info structure that can be used to get the properties of the stored object.

      Program:

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      // C++ program to demonstrate
      // type() method of any class
        
      #include <any>
      #include <iostream>
      #include <string>
        
      int main()
      {
          try {
              any var = 12.0f;
              cout << " \n Type:  "
                   << var.type().name();
        
              var = "Hello World";
              cout << " \n Type:  "
                   << var.type().name();
          }
          catch (bad_any_cast& e) {
              cout << "\n"
                   << e.what();
          }
          return 0;
      }

      chevron_right

      
      

      Output:

      Type:  f 
      Type:  PKc
      

    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:

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      // 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;
      }

      chevron_right

      
      

      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:

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      // 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;
      }

      chevron_right

      
      

      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.



    My Personal Notes arrow_drop_up

    I am a C/C++ developer along with knowledge in C# XAML VBNET

    If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

    Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.




    Article Tags :
    Practice Tags :


    1


    Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.