0

I have the following structure in C++ :

struct wrapper 
{
    // Param constructor
    wrapper(unsigned int _id, const char* _string1, unsigned int _year, 
         unsigned int _value, unsigned int _usage, const char* _string2)
         :
         id(_id), year(_year), value(_value), usage(_usage)
         {
             int len = strlen(_string1);
             string1 = new char[len + 1]();
             strncpy(string1, _string1, len);

             len = strlen(_string2);
             string2 = new char[len + 1]();
             strncpy(string2, _string2, len);
         };
    // Destructor
    ~wrapper()
         {
             if(string1 != NULL) 
                delete [] string1;
             if(string2 != NULL) 
                delete [] string2;
         }

    // Elements
    unsigned int     id;         
    unsigned int     year;       
    unsigned int     value;     
    unsigned int     usage; 
    char*            string1;    
    char*            string2;   
};

In main.cpp let's say I allocate memory for one object of this structure :

wrapper* testObj = new wrapper(125600, "Hello", 2013, 300, 0, "bye bye");

Can I now delete the entire object using pointer arithmetic and a pointer that points to one of the structure elements ?

Something like this :

void*  ptr = &(testObj->string2);

ptr -= 0x14;

delete (wrapper*)ptr;

I've tested myself and apparently it works but I'm not 100% sure that is equivalent to delete testObj.

Thanks.

Daniel
  • 544
  • 1
  • 10
  • 21

3 Answers3

3

Technically, the code like this would work (ignoring the fact that wrapper testObj should be wrapper* testObj and that the offset is not necessarily 0x14, e.g. debug builds sometimes pad the structures, and maybe some other detail I missed), but it is a horrible, horrible idea. I can't stress hard enough how horrible it is.

Instead of 0x14 you could use offsetof macro.

If you like spending nights in the company of the debugger, sure, feel free to do so.

I will assume that the reason for the question is sheer curiosity about whether it is possible to use pointer arithmetic to navigate from members to parent, and not that you would like to really do it in production code. Please tell me I am right.

Zdeslav Vojkovic
  • 14,391
  • 32
  • 45
  • Thanks for the answer. Yes, like you've said it's just curiosity :). – Daniel Apr 23 '13 at 15:30
  • why not? maybe I missed something in the example – Zdeslav Vojkovic Apr 23 '13 at 15:57
  • @ZdeslavVojkovic: Have you tried applying pointer arithmetic to a `void*`, lately? Read my answer. – Lightness Races in Orbit Apr 23 '13 at 16:10
  • ah, that. sure, that's exactly why I have phrased it as 'code like that' instead of 'that code', and glossed over other obvious errors (including 'some other detail I missed'). the point is that 'code like that' which uses pointer arithmetic to go from member to the parent and then deletes the object would indeed work. – Zdeslav Vojkovic Apr 23 '13 at 17:35
1

Can I now delete the entire object using pointer arithmetic and a pointer that points to one of the structure elements ?

Theoretically, yes.

The pointer that you give to delete needs to have the correct value, and it doesn't really matter whether that value comes from an existing pointer variable, or by "adjusting" one in this manner.

You also need to consider the type of the pointer; if nothing else, you should cast to char* before performing your arithmetic so that you are moving in steps of single bytes. Your current code will not compile because ISO C++ forbids incrementing a pointer of type 'void*' (how big is a void?).

However, I recommend not doing this at all. Your magic number 0x14 is unreliable, given alignment and padding and the potential of your structure to change shape.

Instead, store a pointer to the actual object. Also stop with all the horrid memory mess, and use std::string. At present, your lack of copy constructor is presenting a nasty bug.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

You can do this sort of thing with pointer arithmetic. Whether you should is an entirely different story. Consider this macro (I know... I know...) that will give you the base address of a structure given its type, the name of a structure member and a pointer to that member:

#define ADDRESS_FROM_MEMBER(T, member, ptr) reinterpret_cast<T*>( \
  reinterpret_cast<unsigned char *>(ptr) - (ptrdiff_t)(&(reinterpret_cast<T*>(0))->member))
Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37