3

I need efficient way to store values of different types (int, float, QString or std::string, bool) in one of "generic" containers like QVariant.

I want to archive less memory usage.

I prefer a container that doesn't store type of the internal value because it is an overhead.

Which one should I use?

tmporaries
  • 1,523
  • 8
  • 25
  • 39
  • 4
    If you really want a container that does not store the type of the internal value, you could use `std::unique_ptr`. But an object of such a type means "I reference some important data which you no longer know how to read", so it seems pretty pointless to me. – gTcV Feb 06 '14 at 19:45
  • 1
    But can we check the type of any object with `typeid` instruction, can't we? – Vitaly Isaev Feb 06 '14 at 19:50
  • 2
    @VitalyIsaev the major requirement is that the use of `typeid` implicitly means that you must have `RTTI` enabled. Also this kind of solutions rely on `c++ type erasure` techniques and I don't know how much this will influence the ability of your `RTTI` in giving you the right answer. For example http://stackoverflow.com/questions/5450159/type-erasure-techniques – user2485710 Feb 06 '14 at 19:54
  • 1
    As it says [here](http://en.cppreference.com/w/cpp/language/typeid), `typeid` only works the way you want if you use polymorphism. If you use `typeid` on a `void` pointer, it will return you `void*`, if you use it on a dereferenced `void` pointer, the program should not compile because you are not allowed to dereference a `void` pointer. Furthermore, even if it worked the way you want, the libraries you proposed probably would be implemented using the `typeid` operator. – gTcV Feb 06 '14 at 20:05
  • I guess simple union can satisfy my requirements. – tmporaries Feb 06 '14 at 20:05
  • 1
    @tmporaries you are basically an hair away from the _"undefined behaviour theme park"_; with both an `union` and `void pointers`, it's extremely easy to get an UB, at the point that this kind of operations are really useful if you really know what you are doing. If you need space use a compression algorithm on what you have in memory and keep things simple. – user2485710 Feb 06 '14 at 20:09
  • try mine, though it does store the type, no RTTI or allocations though :) http://codereview.stackexchange.com/questions/28939/movable-and-copyable-variant – user1095108 Feb 06 '14 at 20:33

2 Answers2

3

boost::any can hold values of any type, but you have to know what it can possibly hold to be able to extract the value and it allocates memory on the heap for the stored value.

boost::variant on the other hand, can only store values of a set of specified types and you can easily find out what it holds, the sizeof of boost::variant is going to be the sizeof of the largest value type it contains + some extra for the type of the stored value because it does not use heap memory (unless a recursive variant is used).

From memory usage standpoint of view boost::variant may be more efficient because it does not use heap memory. Also, boost::variant is more type-safe that boost::any, the compiler can find more errors at compile time for you.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
-1

I've faced similar question about a year ago. I don't remember the reasoning but I've gone with the boost:any. boost:any does store the typeid that can be used to retrieve the value in desire format.

Here is an example:

#include <iostream>
#include <boost/any.hpp>
#include <string>

int main()
{
    boost::any value;

    for(int i=0; i < 3; i++)
    {
        switch (i)
        {
        case 0:
            value = (double) 8.05;
            break;
        case 1:
            value = (int) 1;
            break;
        case 2:
            //std::string str = "Hello any world!";
            //value = str;
            value = std::string("Hello any world!");
            break;
        }

        if(value.type() == typeid(double))
            std::cout << "it's double type: " << boost::any_cast<double>(value) << std::endl;
        else if(value.type() == typeid(int))
            std::cout << "it's int type: " << boost::any_cast<int>(value) << std::endl;
        else if(value.type() == typeid(std::string))
            std::cout << "it's string type: " << boost::any_cast<std::string>(value) << std::endl;
    }
    return 0;
}

Hope this helps!!

Ankit Patel
  • 1,191
  • 1
  • 9
  • 9