Open In App

std::any Class in C++

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

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:

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

      Program:




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

      
      

      Output:

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

      Program:




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

      
      

      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:




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

      
      

      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:




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

      
      

      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:




      // 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.



    Last Updated : 19 Nov, 2018
    Like Article
    Save Article
    Previous
    Next
    Share your thoughts in the comments
Similar Reads