向向量添加时析构函数内部的双重释放

2022-05-19 00:00:00 destructor vector c++ double-free

嘿,我在鼓机上工作,矢量有问题。

每个序列都有一个样本列表,这些样本以向量的形式进行排序。然而,当样本在向量上被PUSH_BACK时,该样本的析构函数被调用,并导致双重释放错误。

以下是示例创建代码:

class XSample
{
  public:
    Uint8 Repeat;
    Uint8 PlayCount;
    Uint16 Beats;
    Uint16 *Beat;
    Uint16 BeatsPerMinute;

    XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat);
    ~XSample();

    void GenerateSample();

    void PlaySample();
};

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat)
{
    Beats = NewBeats;
    BeatsPerMinute = NewBPM;
    Repeat = NewRepeat-1;
    PlayCount = 0;

    printf("XSample Construction
");
    Beat = new Uint16[Beats];
}

XSample::~XSample()
{
    printf("XSample Destruction
");
    delete [] Beat;
}

和在向量中创建每个样本的‘Dynamo’代码:

class XDynamo
{
  public:
    std::vector<XSample> Samples;

    void CreateSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat);
};

void XDynamo::CreateSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat)
{
    Samples.push_back(XSample(NewBeats,NewBPM,NewRepeat));
}

以下是main():

int main()
{
    XDynamo Dynamo;

    Dynamo.CreateSample(4,120,2);
    Dynamo.CreateSample(8,240,1);

    return 0;
}

程序运行时会发生以下情况:

Starting program: /home/shawn/dynamo2/dynamo 
[Thread debugging using libthread_db enabled]
XSample Construction
XSample Destruction
XSample Construction
XSample Destruction
*** glibc detected *** /home/shawn/dynamo2/dynamo: double free or corruption (fasttop): 0x0804d008 ***

但是,当从析构函数中删除DELETE[]时,程序可以正常运行。

这是什么原因造成的?我们非常感谢您的帮助。


解决方案

问题是您在对象中动态分配内存,而不是声明复制构造函数/赋值运算符。当您分配内存并负责删除它时,您需要定义编译器生成的所有四个方法。

class XSample
{
    public:
        // Pointer inside a class.
        // This is dangerous and usually wrong.
        Uint16 *Beat;
};

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat)
{
    // You allocated it here.
    // But what happens when you copy this object or assign it to another variable.
    Beat = new Uint16[NewBeats];
}

XSample::~XSample()
{
    // Delete here. Turns into double delete if you don't have
    // copy constructor or assignment operator.
    delete [] Beat;
}

执行此操作时,上述内容会发生什么情况:

XSample   a(15,2,2);
XSample   b(a);  // Copy constructor called.
XSample   c(15,2,2);

c = a; // Assignment operator called.

解决此问题的两种方法:

  1. 创建复制构造函数/赋值运算符。
  2. 使用为您执行内存管理的其他对象。

我会使用解决方案2(因为它更简单)。
这也是一个更好的设计。内存管理应该由他们自己的类来完成,您应该集中精力在您的鼓上。

class XSample
{
  public:
    std::vector<Uint16> Beat;
};

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat):
        Beat(NewBeats)
{
         // Notice the vector is constructed above in the initializer list.
}

    // Don't need this now.
XSample::~XSample()
{
}

如果您想用硬方法:
Dynamically allocating an array of objects

如果您想在此处查看编译器版本:
C++ implicit copy constructor for a class that contains other objects

相关文章