Revisiting Heterogeneous Containers

Revisiting Heterogeneous Containers

ive years ago, I explained how to simulate heterogeneous containers by storing raw pointers to polymorphic objects in an STL container. C++ has come along way since: tuples now allow you store arbitrary types in one object. Alternatively, you can replace the raw pointers with shared_ptr. And yet, a heterogeneous container that is free from the hassles of pointer syntax and other arbitrary restrictions is still elusive. This month’s solution presents another technique for implementing heterogeneous containers using the Boost.Any library.


How to store objects of different types in an STL container without the restrictions and complexities of pointers?


Use the Boost.Any library to safely store objects of arbitrary datatypes in a container.

Presenting the Problem
There’s no need to explain why heterogeneous containers are useful. Yet the current techniques of imitating heterogeneity aren’t satisfactory. Take for example the shared_ptr approach. Although this is safer than using raw pointers, it still forces you to use the cumbersome pointer syntax. Worse yet, it only allows you to store objects that belong to the same class hierarchy. What if you want to store unrelated datatypes such as int, std::string, and CDialog in the same container? Theoretically, you can use tuples for this purpose. However, tuples aren’t real containers?they have a statically fixed size and they hold, at most, ten elements. Does that mean you’re still stuck with the burdensome container of pointers approach? Not necessarily. Class boost::any, which is part of the Boost.Any library, overcomes many of the limitations of traditional heterogeneous containers.

Anything Goes
boost::any allows for type-safe storage and the retrieval of arbitrary types. The main difference between this class and other indiscriminate types (like unions, variant_t, etc.) is that the caller must know the exact type of the value stored in boost::any in order to access it.

Author’s Note: Before you can use boost::any, you need to download the relevant boost libraries and install them. Note also that according to the Boost convention, class any and its related helper functions are declared in namespace boost.

boost::any has a default constructor which creates an empty any object, and another non-explicit constructor which takes an object of an arbitrary type. The copy constructor and assignment operator enable you to copy and assign any type of object to any:

boost::any a;a=10;a=std::string("I'm a string");boost::any a2(a);

You can store any object that meets the copy-constructible and assignable requirements in any. To access the value stored in any, use the boost::any_cast function. any_cast is similar to operator dynamic_cast: its first argument is a type name, and the second is the actual any object. If the type name matches the object’s type, any_cast returns a reference to the stored object. Otherwise, it throws a boost::bad_any_cast exception:

try{ std::string test=boost::any_cast (a);}catch(boost::bad_any_cast & e){ cout<<"it's not a string!" <

any_cast also has a pointer version which doesn't throw. If the types of the target and the source don't match, a NULL pointer is returned:

string *ptest=boost::any_cast (&a);if(ptest){ cout<<*ptest<

any grants access to the stored object only if you know its type. Since any can contain at most one object at a time, assigning a new object to it overrides the previously stored value (and its type). The any_cast operations above are successful because the last object assigned to any was a string.

Creating a Heterogeneous Container
The following example uses a vector of any to store four unrelated objects:

using std::vector; using std::string;using std::make_pair;using std::for_each;int main(){ vector bag; bag.push_back(string());  bag.push_back(80); bag.push_back(myclass()); //store a pair bag.push_back(make_pair(string("PAGE_SIZE"), 1024)); for_each(bag.begin(), bag.end(), retrieve);}

bag really looks like a heterogeneous container! But how do you access the elements stored in it? First, access the vector's elements as usual, using iterators (as shown in the example) or the [] notation. Next, use the any_cast function to retrieve the value stored in each element:

using std::string;using std::map;using std::cout;using std::endl;void retrieve(boost::any & a){ if(string *pstr = boost::any_cast(&a)) {  cout<<"string is: "<< *pstr < (&a)) {  cout<<"int: "<< *pi <(&a)) {  cout<< "myclass: " < *pmap   =boost::any_cast >(&a)) {  cout<< "map: " << pmap->first <<" "    << pmap>second >>endl; } else {  cout<< "unknown type" << endl; }}

Unlike dynamic_cast, boost::any supports non-polymorphic objects and built-in datatypes as well. There's no need to worry about performance either?as opposed to dynamic_cast, boost::any_cast actually uses static_cast under the hood, so it's pretty efficient.

Additional Member Functions
any's destructor destroys the object stored in it. However, because the destructor calls delete and never delete[], you should wrap pointers to arrays in an appropriate smart pointer before storing them in any.

The empty() member function returns a Boolean value indicating whether the any object contains a value:

boost:any anybody;cout<

any objects. Finally, the type() member function returns a reference to std::type_info which you can use in a typeid expression:

if (typeid(any1.type())==typeid(int)){ int val=boost::any_cast (any1);}

Safe and Efficient
boost::any brings STL containers closer to the SmallTalk-style concept of heterogeneous containers, with minimal performance overhead and without compromising type-safety. Remember that boost::any is also useful in other frameworks that require indiscriminate types. What's still missing in standard C++ is a reflection library that safely reconstructs objects and their types from a collection.

Share the Post:
XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes

ransomware cyber attack

Why Is Ransomware Such a Major Threat?

One of the most significant cyber threats faced by modern organizations is a ransomware attack. Ransomware attacks have grown in both sophistication and frequency over the past few years, forcing

data dictionary

Tools You Need to Make a Data Dictionary

Data dictionaries are crucial for organizations of all sizes that deal with large amounts of data. they are centralized repositories of all the data in organizations, including metadata such as

©2023 Copyright DevX - All Rights Reserved. Registration or use of this site constitutes acceptance of our Terms of Service and Privacy Policy.

Sitemap