Jump to content
  • Advertisement
  • entries
  • comments
  • views

Code snippet for typesafe void* userdata

Sign in to follow this  
Servant of the Lord


Just tossed this piece of code together - it wraps void* points with asserts() to ensure you are getting the same type that you originally set.
Normally I shy away from void* pointers as I feel like they are indicators of bad design, but sometimes you need to use them, and when you do, they might as well be type-safe.

This is kinda a lightweight alternative to boost::any, but not designed by a peer-reviewed team of professionals who also have seats on the C++ standards committee. laugh.png

Requires C++11's typeid(), and RTTI enabled.#include #include #include //Quick macro to replace my real Assert() function, just for this file.#define Assert(condition, message) assert(condition && message) //Holds any type of user-given pointer that can be cast to void, and does run-time checks on the type of the data when retrieving it.//Ownership is *not* taken. It is the original owner's responsibillity to ensure the lifetime of the object when//someone tries to retrieve the pointer later. The Userdata class itself never de-references the pointer.class Userdata{public: Userdata() = default; template Userdata(UserType *data) { this->Set(data); } //Sets a user-spe template void Set(UserType *data) { //Save the pointer (cast to void*), and the type's RTTI information, so we can validate on retrieval. this->type_info = &typeid(UserType); this->userdata = data; } template UserType *Get() { //Validate that we've actually set *anything*. Assert(this->type_info, "We never set any data, so we can't retrieve any."); //Validate that we are getting the same type that we initially set. Assert((*this->type_info) == typeid(UserType), "The types don't match - we can't retrieve the userdata safely."); return static_cast(this->userdata); } void Reset() { this->type_info = nullptr; this->userdata = nullptr; } private: //A pointer to the global compiler-specific (but standardized) type_info for this type (the type that Userdata's void* points to). //C++11 guarantees that "The lifetime of the object referred to by [typeid()'s return value] extends to the end of the program." (N3337 5.2.8) const std::type_info *type_info = nullptr; //A pointer to the user-defined data. void *userdata = nullptr;}; //Manages a FILO stack of void pointers in a type-safe way.//This class does not take any ownership of the data pointed to.class UserdataStack{public: UserdataStack() = default; ~UserdataStack() = default; template void Push(UserType *userdata) { this->stack.push_back(Userdata(userdata)); } template UserType *Get() { Assert(!this->stack.empty(), "The stack is empty - we can't retrieve any userdata."); return this->stack.back().Get(); } void Pop() { if(!this->stack.empty()) { this->stack.pop_back(); } } //Pops the stack, and returns the pointer previously pointed to. template UserType *Take() { UserType *data = this->Get(); this->Pop(); return data; } void Clear() { this->stack.clear(); } private: std::vector stack;};

Compilable code on Ideone.com

Note: By design, the Userdata/UserdataStack classes don't take ownership of the data. I guess that's another difference than with boost::any - though you could always just pass boost::any some pointers.
Sign in to follow this  


Recommended Comments

Done. I can't see any way to get to 'Sweet snippets' from the main site without following that link you just posted. Is it not integrated into the rest of the site yet? The dates on the test submissions are from 8 months ago.

Share this comment

Link to comment

It was Mike's project and to be honest I'm not sure where it's at. He hasn't been asking me to push them at all so... just looked at the page and yea still seems to have a few bugs in it. I'll let him know about it.

Share this comment

Link to comment

Well, if it's not ready or low priority, I could just toss it into an article instead, though it'd just be a copy+paste of the code, not a real article.

Share this comment

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!