tags:

views:

106

answers:

3

I'm having a (design) problem: I'm building an interpreter and I need some storage for variables. There are basically two types of content a variable here can have: string or int.

I'm using a simple class for the variables, all variables are then stored in a vector.

However, as a variable can hold a number or a string, I don't want C++ to allocate both and consume memory for no reason.

That's why I wanted to use unions:

union
{
 string StringValue;
 int IntValue;
}

However, strings don't work with unions.

  • Is there any workaround so no memory gets eaten for no reason?
+5  A: 

You may check out Boost.Variant

typedef boost::variant<std::string, int> Variable;

(Although that "wastes" extra memory - the size of a variant is something like the size of the largest type plus a word or so for bookkeeping - can't see how you could do with less anyway.)

UncleBens
Are you sure this isn't actually slower/even consuming more memory than just allocating both int and string?
sub
strings in C++ are variable length entities. You can never know just how much memory a string will hold until it has a value.
wheaties
@sub: Boost variant is quite efficient. In any case it's *easier*, and that's what matters.
GMan
@wheaties: A `std::string` is, I believe, of fixed length. The memory for the string itself can be allocated elsewhere.
David Thornley
@David Thornley that is correct. However, seeing as I've had people in real life go on to believe that a `const char*` only occupies the space of a pointer and nothing more, regardless of what it points to, I always say something with an underlying variable length array holds more than it appears to hold.
wheaties
@sub: It's not going to use more memory than that, and it probably won't be that slow either. The alternatives aren't exactly free either. With a union you'll still have to know somehow which field is valid. If you store pointers to string, this will most likely require you to allocate them dynamically which again isn't free.
UncleBens
`variant` does perform optimization (predicated on `BOOST_VARIANT_MINIMIZE_SIZE`) to minimize the discriminating `which_` private member, but the structure will still be padded as if it's a `struct{ string; int; };`. The advantage is that the `variant` is a good place to keep that one bit of state, so it shouldn't be duplicated elsewhere.
Potatoswatter
+2  A: 

However, as a variable can hold a number or a string, I don't want C++ to allocate both and consume memory for no reason.

Why not? How does four or eight or sixteen extra bytes hurt?

Unless you have a good reason, I don't think wasting 1KB is a lot.

If you want to use a union with a string, you can instead use pointers. Either use string *, int, string *, int *, or const char *, int or const char *, int *, as the union member types.

strager
Thanks, I prefer your solution to throwing in an extra library for that now!
sub
A: 

I would not worry about the extra storage of a single integer. The overhead of correctly managing a variant or discriminated union with a string pointer is going to be much worse than using the extra storage associated with a single field.

D.Shawley