Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Sweet Snippets - Public free and open repository of game development source


Like
0Likes
Dislike

[Userdata] Type-checking void* wrapper

Tags: C++ C++11 void* RTTI
A wrapper around void* for passing unknown data types of any size. Asserts upon retrieval if the type you are trying to retrieve does not match the type you originally gave. Does not take ownership of the data.
userdata.h - The userdata class itself.
#pragma once

#include <typeinfo>
#include <cassert>
 
//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<typename UserType>
        Userdata(UserType *data)
        {
                this->Set(data);
        }
        
        //Sets a user-spe
        template<typename UserType>
        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<typename UserType>
        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<UserType*>(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;
};


main.cpp - Example usage
#include <iostream>
#include <string>
  
#include "Userdata.h"
 
int main()
{
    int myInt = 357;
    float myFloat = 7.53f;
    std::string myString = "This is a test";
    
    Userdata userdataA(&myString);
    
    Userdata userdataB;
    userdataB.Set(&myInt);
    
    int *intPtr = userdataB.Get<int>();
    std::cout << "int:\t\t" << *(intPtr) << " (should be " << myInt << ")" << std::endl;
    
    userdataB.Set(&myFloat); //Overwrites the first pointer set.
    
    //Asserts, because it's the wrong type.
    //char *test = userdataB.Get<char>();
    
    std::cout << "std::string:\t\"" << *(userdataA.Get<std::string>()) << "\" (should be \"" << myString << "\")" << std::endl;
    std::cout << "float:\t\t"     << *(userdataB.Get<float>())       << " (should be " << myFloat  << ")" << std::endl;
    
    return 0;
}


. -





0 Comments


PARTNERS