首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在向量中添加时,析构函数内部的双重释放

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

Stack Overflow用户
提问于 2010-05-12 03:57:06
回答 5查看 4.1K关注 0票数 2

嘿,我在一个鼓机上工作,我遇到了矢量的问题。

每个序列都有一个样本列表,这些样本在一个向量中排序。但是,当样本在向量上为push_back时,将调用该样本的析构函数,并导致双重释放错误。

以下是示例创建代码:

代码语言:javascript
复制
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”代码:

代码语言:javascript
复制
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():

代码语言:javascript
复制
int main()
{
    XDynamo Dynamo;

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

    return 0;
}

这就是程序运行时发生的事情:

代码语言:javascript
复制
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 []时,程序可以正常运行。

是什么导致了这种情况?任何帮助都是非常感谢的。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-05-12 06:32:33

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

代码语言:javascript
复制
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;
}

当您这样做时,上面的内容会发生什么:

代码语言:javascript
复制
XSample   a(15,2,2);
XSample   b(a);  // Copy constructor called.
XSample   c(15,2,2);

c = a; // Assignment operator called.

有两种方法可以解决这个问题:

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

我会使用解决方案2(因为它更简单)。

这也是一个更好的设计。内存管理应该由他们自己的类来完成,你应该集中精力在你的鼓上。

代码语言:javascript
复制
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

票数 4
EN

Stack Overflow用户

发布于 2010-05-12 04:00:55

你需要一个合适的复制构造函数和赋值操作符,因为你有一个非平凡的析构函数(更准确地说,因为你的类包装了一个内存分配)。请看“三大法则”:

  • http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29

更新:

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

票数 8
EN

Stack Overflow用户

发布于 2010-05-12 04:00:41

编译器添加了一个默认的复制构造函数,这意味着在samples.push_back(...)期间XSample::Beats会出现别名。您应该添加一个复制构造函数来正确初始化XSample,方法可能是从参数中复制XSample::Beats

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2814013

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档