删除联盟中的指针

时间:2015-04-16 10:25:35

标签: c++ pointers

我尝试了一些有趣的代码(至少对我而言!)。在这里。

#include <iostream>

struct myStruct{
    int one;

    /*Destructor: Program crashes if the below code uncommented*/
    /*
    ~myStruct(){
        std::cout<<"des\n";
    } 
    */
};
struct finalStruct {
    int noOfChars;
    int noOfStructs;

    union { 
        myStruct *structPtr;
        char *charPtr;
    }U;

};
int main(){
    finalStruct obj;
    obj.noOfChars = 2;
    obj.noOfStructs = 1;
    int bytesToAllocate = sizeof(char)*obj.noOfChars 
                        + sizeof(myStruct)*obj.noOfStructs;

    obj.U.charPtr = new char[bytesToAllocate];
    /*Now both the pointers charPtr and structPtr points to same location*/

    delete []obj.U.structPtr;
}

我已将内存分配给charPtr并使用structPtr删除。当我向myStruct添加析构函数时崩溃,否则没有问题。

这里究竟发生了什么。据我所知,delete []将调用析构函数的次数与new []中给出的次数相同。为什么在myStruct中没有析构函数时它不会崩溃?

4 个答案:

答案 0 :(得分:8)

首先,存储一个union的一个成员,然后以你正在做的方式读取另一个成员是Undefined Behavior,简单明了。这是错的,任何事情都可能发生。

除此之外,你尝试使用联盟的类型双关语很可能实际上有效(但记住保证)。如果是这种情况,会发生以下情况:

您分配bytesToAllocate类型char对象的数组,并将该地址存储在工会指针中。

然后,在联合指针上调用delete[],键入为myStruct* 。这意味着它假定它是一个myStruct个对象的数组,它将在每个对象上调用析构函数。但是,该数组不包含任何myStruct个对象,它包含char个对象。实际上,数组的字节大小甚至不是myStruct大小的倍数!必须彻底混淆delete实施。它可能将第一个sizeof(myStruct)字节解释为一个myStruct对象,并在这些字节中调用析构函数。然后,还剩下少于sizeof(myStruct)个字节,但仍有一些剩余,所以析构函数会在那些不完整的字节上调用,超出数组,然后就会出现欢闹。

当然,由于这只是UB,我对上述行为的猜测可能会有所不同。简单明了,你已经把它弄糊涂了,所以它很混乱。

答案 1 :(得分:2)

delete做了两件事,调用析构函数并释放内存。

您为一种类型分配数据,但如果伪造另一种类型则删除。 你不应该这样做。在C / C ++中可以做很多事情,看一下IOCCC以获得更多灵感: - )

没有任何功能且只有plain old data的C ++结构本身就是一个POD。它在创建/删除时从不调用构造函数/析构函数。 甚至不是标准的c-tors / d-tors。仅出于性能原因。

具有(EDIT)用户定义的复制赋值运算符,虚拟函数或d-tor的结构在内部稍微复杂一些。它有一个成员函数指针表。

如果使用chars分配内存块,则不会初始化此表。当您尝试使用非POD类型删除此内存块时,它首先调用析构函数。并且由于析构函数指针未初始化,它会调用内存空间中的任何内存块,认为它是函数。这就是崩溃的原因。

答案 2 :(得分:2)

它的工作原理是因为myStruct没有析构函数。 [编辑:我现在看到你试过了,它确实崩溃了。我会发现这个问题很有趣,为什么它会与那个dtor崩溃,因为dtor不能访问该对象的任何内存。]

正如其他人所说,free []的第二个功能,除了可能调用元素的dtors(这里没有发生,如上所述)是释放内存。

这在您的实现中非常有效,因为通常免费的存储实现只是为此目的分配一块内存,其大小保存在该内存中的簿记位置。大小(一旦分配)是类型无关的,即不是从free上的指针类型派生的。参看How does delete[] "know" the size of the operand array?。 malloc like,类型不可知分配器返回内存块并且很高兴。

请注意,当然,你所做的是夸张的,不要在家里这样做,不要发布它,并使ppl签署非责任分歧,不要在核设施中使用它,并始终从主要返回int ()。

答案 3 :(得分:1)

问题是obj.U.structPtr指向一个结构,它可以有一个构造函数和析构函数。

delete也需要正确的类型,否则无法调用析构函数。

因此,使用char创建new数组并将其删除为struct指针是违法的。

如果您使用mallocfree,那就没关系。这不会调用构造函数和析构函数。