使用指针算术和指向该结构元素的指针释放结构

时间:2013-04-23 15:13:56

标签: c++ structure pointer-arithmetic

我在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;   
};

在main.cpp中,假设我为这个结构的一个对象分配内存:

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

现在可以使用指针算法和指向其中一个结构元素的指针删除整个对象吗?

这样的事情:

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

ptr -= 0x14;

delete (wrapper*)ptr;

我已经测试过自己并且显然它有效,但我并非100%确定这相当于delete testObj

感谢。

3 个答案:

答案 0 :(得分:3)

从技术上讲,这样的代码可以工作(忽略wrapper testObj应该是wrapper* testObj并且偏移量不一定是0x14的事实,例如调试版本有时填充结构,也许我错过了一些其他细节,但这是一个可怕的,可怕的想法。我不能过分强调它是多么可怕。

而不是0x14您可以使用offsetof宏。

如果您喜欢在调试器的陪伴下度过夜晚,请务必随时这样做。

我将假设这个问题的原因纯粹是关于是否可以使用指针算法从成员导航到父级,而不是你想在生产代码中真正做到这一点。请告诉我我是对的。

答案 1 :(得分:1)

  

我现在可以使用指针算法和指向其中一个结构元素的指针删除整个对象吗?

理论上,是的。

您赋予delete的指针需要具有正确的值,并且该值是否来自现有的指针变量,或者通过"调整"并不重要。以这种方式。

您还需要考虑指针的类型;如果没有别的,你应该在执行算术之前转换为char*,这样你就可以单步执行。您当前的代码无法编译,因为ISO C++ forbids incrementing a pointer of type 'void*'void有多大?)。

但是,我建议这样做。鉴于对齐和填充以及结构改变形状的可能性,您的幻数0x14是不可靠的。

而是存储指向实际对象的指针。同时停止所有可怕的记忆混乱,并使用std::string。目前,您缺少复制构造函数是一个令人讨厌的错误。

答案 2 :(得分:0)

可以用指针算法做这种事情。你应该是一个完全不同的故事。考虑一下这个宏(我知道......我知道......),它将为您提供给定其类型的结构的基址,结构成员的名称和指向该成员的指针:

#define ADDRESS_FROM_MEMBER(T, member, ptr) reinterpret_cast<T*>( \
  reinterpret_cast<unsigned char *>(ptr) - (ptrdiff_t)(&(reinterpret_cast<T*>(0))->member))