static_cast



  • On 08/05/2014 at 20:07, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R14 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi folks,
     
    just looking for a little bit of education here. I'm using static_cast to get data out of a void reference, like the following:

    class_function(int id,void *link)
    {
        MyStruct_1 *mst_1 = NULL;
        MyStruct_2 *mst_2 = NULL;
     
        if(id == 1)
        {
            mst_1 = (MyStruct_1* )Link;
        }
        else if(id == 2)
        {
            mst_2 = (MyStruct_2* )Link;
        }
     
        // rest of code etc
    }
    

    As far as the function being called and working, everything seems fine with the above. But what  I'm wanting to know is, is it possible to get the link type by testing it against the different struct types? Something like this:

    class_function(void *link)    // int id removed
    {
        MyStruct_1 *mst_1 = NULL;
        MyStruct_2 *mst_2 = NULL;
     
        if(link == static_cast<MyStruct_1*>(link))
        {
            mst_1 = (MyStruct_1* )Link;
        }
        else if(link == static_cast<MyStruct_2*>(link))
        {
            mst_2 = (MyStruct_2* )Link;
        }
    }
    

    I know the above doesn't work, but it might help to illustrate what I'm getting at! Is it possible to test a static_cast's type with something like the above? Or will I have to use the additional "int id" argument to get/set it's type?
     
    Cheers,
     
    WP.
     
    EDIT: further reading is suggesting that there's no particularly safe way of doing this, though I'd still be interested to hear from anyone who'd like to provide some thoughts.



  • On 09/05/2014 at 02:38, xxxxxxxx wrote:

    Hi,

    why do you need to use void pointer at all ?

    This is one possibility to do something like this.

      
        
        
        class Base
        {
        public:
        	virtual int GetType() { return 0; }
        	virtual ~Base() {}
        };
         
        class MyStruct_1 : public Base
        {
        public:
        	virtual int GetType() { return 1; }
        };
         
        class MyStruct_2 : public Base
        {
        public:
        	virtual int GetType() { return 2; }
        };
         
         
        void class_function(Base *link) {
         
        	MyStruct_1 *mst_1 = NULL;
        	MyStruct_2 *mst_2 = NULL;
         
        	if (link->GetType() == 1)	{
        		mst_1 = (MyStruct_1* )link;
        		printf("type 1 \n");
        	}
        	else if (link->GetType() == 2) {
        		mst_2 = (MyStruct_2* )link;
        		printf("type 2 \n");
        	}
        }
    

    Another more complicated possibility would be to store ID into the void pointer it self.
    This is faster but much much more complicated and dangerous if you do not know how to do this, so I would not recommend this way :)

    regards,
    Remo



  • On 09/05/2014 at 06:21, xxxxxxxx wrote:

    Hi Remo,
     
    I can hear your advice! I'm no expert that's for sure!
     
    The reason was partly to learn (I picked something similar up in a Message function I think to do with descriptions - didn't fully understand what it was doing at the time and thus piqued my interest), but also because I have a scenario where I'm wishing to pass one of 3 possible structs to another function to work with. These structs could then be one out of an array themselves, where that array might be held in an array also. It's just getting a little tedious having to always check for id's and index values or passing on so many arguments to get the operation in another function going. The data setup I have feels good so far as the working theory of it is concerned (it feels like a stable setup even though it might sound a little cumbersome), but it's just getting tiring to code with.
     
    Your example reminds me of a function I have for testing some GeUserArea()'s with by using GeUserArea()->GetID(). It hadn't occurred to me to try something like that. Otherwise, storing the id in the void itself - does this mean something trixy-dixy like putting an int at the start of each struct, and plain assume that the passed void has an "int id" as it's first variable?
     
    WP.



  • On 09/05/2014 at 07:42, xxxxxxxx wrote:

    does this mean something trixy-dixy like putting an int at the start of each struct, and plain assume that the passed void has an "int id" as it's first variable?
     
    Yes this would be also 3th possibility :)
    Something like this could work.
    But it is of course Dangerous (tm)!!!

      
        
        
        struct Base 
        {
        	int m_id;
        	Base() : m_id(0) {}
        };
        struct MyStruct_1 : public Base
        {
        	MyStruct_1() { m_id = 1; }
        };
         
        struct MyStruct_2 : public Base
        {
        	MyStruct_2() { m_id = 2; }
        };
         
        void class_function(void *link) {
         
        	MyStruct_1 *mst_1 = NULL;
        	MyStruct_2 *mst_2 = NULL;
         
        	if (static_cast<Base*>(link)->m_id == 1)	{
        		mst_1 = (MyStruct_1* )link;
        		printf("type 1 \n");
        	} else if (static_cast<Base*>(link)->m_id == 2) {
        		mst_2 = (MyStruct_2* )link;
        		printf("type 2 \n");
        	}
        }
    

    Now if you pass something totally different you will get UB and may be crash or may be something even worse :)
    So first solution is recommended.



  • On 09/05/2014 at 08:05, xxxxxxxx wrote:

    Well here is 3th solution, even more dangerous :)
    Please do not try this at home!

      
        
        
        struct alignas(16) MyStruct_1
        {
        	double b;
        };
         
        struct alignas(16) MyStruct_2
        {
        	float a;
        };
         
        //decode id from properly aligned void pointer.
        inline int   GetId(void *ptr){ return reinterpret_cast<int64_t>(ptr) & 0x7; }
         
        // encode id into properly aligned void pointer, id can be [0..7]
        inline void* SetId(void *ptr, int id){
        	if (id < 0 || id >= 0x7) { printf("id is too big or negative !!! \n"); throw; }
        	if ((reinterpret_cast<int64_t>(ptr) & 0x7) != 0){ printf("wrong ptr alignment !!! \n"); throw; }
        	return reinterpret_cast<void*>(reinterpret_cast<int64_t>(ptr) | id); 
        }
         
         
        void class_function(void *link) {
         
        	MyStruct_1 *mst_1 = NULL;
        	MyStruct_2 *mst_2 = NULL;
         
        	if (GetId(link) == 1)	{
        		mst_1 = (MyStruct_1* )link;
        		printf("type 1 \n");
        	} else if (GetId(link) == 2) {
        		mst_2 = (MyStruct_2* )link;
        		printf("type 2 \n");
        	}
        }  
          
        void test()
        {
        	MyStruct_2  s2;
        	void* ptr2 = SetId(&s2, 2);
        	class_function(ptr2);
         
        	MyStruct_1  s1;
        	void* ptr1 = SetId(&s1, 1);
        	class_function(ptr1);
        }  
        
    

Log in to reply