It works, but I found that on my system this makes the Entity class's size explode to 352 bytes. There will be hundreds of entities, so this is way too big for a class that's supposed to be lightweight.

Most instances of the class don't have any userdata, so that's mostly wasted memory.

What are my options here?

I guess I could make the maps into pointers and work with new/delete, so only the instances that need userdata could have the maps allocated. Could that be the way to go?

I have no idea what you are trying to accomplish
<nolyc> You're trying to do X, and you thought of solution Y. So you're asking about solution Y, without even mentioning X. The problem is, there might be a better solution, but we can't know that unless you describe what X is.

> I tried subclassing Entity, but I found that this leads to loads of spaghetti code
If it has an `is a' relationship, only then you may consider subclassing

> Most instances of the class don't have any userdata
¿what's the purpose of `userdata'?
If some instances would not use it, then it may be a pointer.

> I guess I could make the maps into pointers and work with new/delete
maps are just a couple of pointers

Basically, I have a game world which is mainly a collection of instances of this Entity class.

Entities have a position, rotation, physics properties and a pointer to a 3d model, and this is how it's defined in the library.

In the application that links to the library, it might be useful for some of the entities to contain some extra data (which I'm calling user-data here) such as the name of a character, the time since it last drank some magic potion, the location of their house, the item they might be holding in their hand etc...

Since the Entity class is defined in the library (and intended to be reused in other projects), these cannot be added as class members directly, and by far not all entities will need these properties.

> a class that's supposed to be lightweight.
> Most instances of the class don't have any userdata, so that's mostly wasted memory.
> What are my options here?

The solution that jumps to the mind immediately, is to have the objects hold extrinsic state (in a shared lookup table). The object size is not affected at all; and for most instances (do not have any user data), there is zero memory overhead.

There are two issues with the existing code:float& getUserFloat(const std::string& key){ return userFloats[key]; }

One, it will needlessly burn memory if the object does not have any user data (or if user data with this key does not exist). Ideally, use find() instead of the subscript operator.

> In the application that links to the library,
> it might be useful for some of the entities to contain some extra data (which I'm calling user-data here)
> Since the Entity class is defined in the library,
> these cannot be added as class members directly