添加到向量时在析构函数内部进行双重释放

发布于 2024-09-01 08:36:24 字数 1616 浏览 16 评论 0原文

嘿,我正在使用鼓机,并且遇到矢量问题。

每个序列都有一个样本列表,并且样本在向量中排序。然而,当样本在向量上被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\n");
    Beat = new Uint16[Beats];
}

XSample::~XSample()
{
    printf("XSample Destruction\n");
    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 [] 时,程序完美运行。

是什么原因造成的?非常感谢任何帮助。

Hey, I am working on a drum machine, and am having problems with vectors.

Each Sequence has a list of samples, and the samples are ordered in a vector. However, when a sample is push_back on the vector, the sample's destructor is called, and results in a double free error.

Here is the Sample creation code:

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\n");
    Beat = new Uint16[Beats];
}

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

And the 'Dynamo' code that creates each sample in the vector:

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));
}

Here is main():

int main()
{
    XDynamo Dynamo;

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

    return 0;
}

And this is what happens when the program is run:

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 ***

However, when the delete [] is removed from the destructor, the program runs perfectly.

What is causing this? Any help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

埖埖迣鎅 2024-09-08 08:36:24

您需要一个适当的复制构造函数和赋值运算符,因为您有一个不平凡的析构函数(更准确地说,因为您的类包装了内存分配)。请参阅“三巨头规则”:


更新:

正如 Martin York 在评论中提到的,这个答案实际上只是解决了问题的直接原因,但并没有真正提出解决问题的最佳方法。修复它,即使用自动管理资源的 RAII 类成员。从表面上看(给定示例代码),Beat 成员可能是 std::vector 而不是指向手动分配数组的指针。 vector<> 成员将允许类不需要特殊的 dtor、copy ctor 或赋值运算符 - 所有这些部分都将自动提供给 Beat 成员(如果它)是一个向量

You need a proper copy constructor and assignment operator since you have a non-trivial destructor (more accurately because your class wraps a memory allocation). See the 'Rule of the Big 3':


Update:

As Martin York mentioned in the comments, this answer really just addresses the immediate cause of the problem but doesn't really suggest the best way to fix it, which is to use RAII class members that manage the resources automatically. On the face of it (given the example code), the Beat member might be a std::vector<> instead of a pointer to a manually allocated array. A vector<> member would allow the class to not need a special dtor, copy ctor or assignment operator - all those pieces would be automatically provided for the Beat member if it were a vector<>.

ぶ宁プ宁ぶ 2024-09-08 08:36:24

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

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()
{
}

如果您想以困难的方式做到这一点:
动态分配对象数组

如果你想在这里查看编译器版本:
包含 other 的类的 C++ 隐式复制构造函数对象

The problem is you are dynamically allocating memory in your object but not declaring a copy constructor/ assignment operator. When you allocate memory and are responsible for deleting it you need to define all FOUR methods that the compiler generates.

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

What happens to the above when you do:

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

c = a; // Assignment operator called.

Two ways to solve this:

  1. Create the copy constructor/assignment operator.
  2. Use another object that does memory management for you.

I would use solution 2 (as it is simpler).
Its also a better design. Memory management should be done by their own class and you should concentreate on your drums.

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()
{
}

If you want to do it the hard way:
Dynamically allocating an array of objects

If you want to see what the compiler versions look here:
C++ implicit copy constructor for a class that contains other objects

你没皮卡萌 2024-09-08 08:36:24

编译器添加了一个默认的复制构造函数,这意味着 XSample::Beatssamples.push_back(...) 期间获得了别名。您应该添加一个正确初始化 XSample 的复制构造函数,可能是通过从参数复制 XSample::Beats 来实现的。

The compiler added a default copy constructor which means that XSample::Beats got aliased during samples.push_back(...). You should add a copy constructor that initializes XSample correctly, probably by copying XSample::Beats from the argument.

是伱的 2024-09-08 08:36:24

Vector 正在复制构造您的 XSample(使用编译器生成的默认复制构造函数),因此在破坏副本时会导致问题。您可以在向量中存储指向 XSample 的指针或编写适当的复制构造函数。

vector is copy-constructing your XSamples (using the compiler generated default copy constructor), and as a result, causing problems when it destructs the copy. You can store pointers to XSample in the vector or write a proper copy constructor.

我还不会笑 2024-09-08 08:36:24

发生的情况是 Samples.push_back() 将其参数复制到向量中。由于 XSample 没有定义复制构造函数,因此编译器会创建一个默认构造函数,该构造函数执行浅复制。这意味着向量中原始和副本中的 Beat 指针都指向同一内存。然后,原始内容在 push_back() 末尾被破坏,删除 Beat 指针。

在 main 的末尾,Dynamo 被析构,调用每个元素的析构函数。这会尝试删除已删除的 Beat 指针,从而导致双重删除错误。

What is happening is that Samples.push_back() copies its argument into the vector. Since XSample doesn't have a copy constructor defined, the compiler creates a default constructor, which does a shallow copy. This means that the Beat pointer in both the original and the copy in the vector point to the same memory. The original is then destructed at the end push_back(), deleting the Beat pointer.

At the end of main, Dynamo is destructed, calling the destructor of each of the elements. This tries to delete the already deleted Beat pointer, resulting in your double delete error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文