C++ 对对象数组调用delete[]会无故损坏堆

C++ 对对象数组调用delete[]会无故损坏堆,c++,delete-operator,heap-corruption,C++,Delete Operator,Heap Corruption,但是对于这个特殊的问题,它的代码非常简单,类非常简单。我真的不知道这里会出什么问题。我没有两次调用delete[],我没有调用delete而不是delete[],我在保存new[]结果的同一指针上调用它。我想,在这个特殊的delete[]之前,可能还有其他一些代码破坏了堆,但我仔细检查了我的自定义字符串类(只有一个处理原始指针的类),它100%正常工作 在完整的代码中,您可以看到一些调试输出。它在尝试扫描文件夹中的第三个文件或第四个文件后崩溃,随机 void Files::Push(const

但是对于这个特殊的问题,它的代码非常简单,类非常简单。我真的不知道这里会出什么问题。我没有两次调用
delete[]
,我没有调用
delete
而不是
delete[]
,我在保存
new[]
结果的同一指针上调用它。我想,在这个特殊的
delete[]
之前,可能还有其他一些代码破坏了堆,但我仔细检查了我的自定义字符串类(只有一个处理原始指针的类),它100%正常工作

在完整的代码中,您可以看到一些调试输出。它在尝试扫描文件夹中的第三个文件或第四个文件后崩溃,随机

void Files::Push(const File& f)
{
    if(!s_)
    {
        files_ = new File[++s_];
        files_[0] = f;
        return;
    }

    File* tmp = new File[++s_];
    memcpy(tmp, files_, (s_-1) * sizeof(File));
    tmp[s_-1] = f;

    delete[] files_;

    files_ = tmp;
}
编辑:

我修复了它,制作了适当的深度复制构造函数,并为文件分配了任务,也为文件分配了任务

class File
{
public:
    File();
    File(const wchar_t* n, ulong b, bool isf, bool hid, bool sys);

    const Fname& Name() const;
    ulong Bytes() const;
    void AddBytes(ulong b);
    bool IsFolder() const;
    bool IsHidden() const;
    bool IsSystem() const;

    void PushFile(const wchar_t* n, ulong b, bool isf, bool hid, bool sys);
    void PushFile(const File& f);

private:
    void SetBytes(ulong b);
    ulong BytesTaken(ulong b) const;
    // Data
    Fname fn_;
    Files fs_;
    // Folder, Hidden and System attributes stored here in upper bits
    ulong bytes_;
    ulong bytes_taken_;
};
现在,在文件中使用文件根本不是问题。和使用原始指针一样(当然,如果您知道自己在做什么的话)。如果我不尝试在非POD类上使用这种愚蠢的memcopy来简化事情,一切都会好起来的


谢谢你的帮助

请注意两件事:

  • delete[]
    为所有被删除的数组元素调用析构函数
  • memcpy
    只复制字节,而不需要使用复制构造函数复制需要复制的内容
如果您的
文件
类具有非基元类型的内容,例如指针,您就有麻烦了,因为当您
memcpy
时,您没有正确复制这些成员。当您
delete[]
原始数组时,会为已删除元素的成员调用析构函数,这会使
tmp
副本中的值无效

最好不要将
memcpy
用于基本类型以外的任何类型(例如整数)。使用
std::vector
存储
文件
对象,并使用
push_back
向向量添加新项

我的自定义字符串类(唯一一个处理原始指针的类)

你的
文件
类有一个原始指针,所以它被窃听了。您的
File
类包含一个
Files
对象,因此这也是错误的

非POD类型(如
File
)上的
memcpy
是另一个bug


不要使用原始指针,或者如果您坚持,请确保您的类具有正确的复制语义。不要memcpy对象,使用复制构造函数和赋值。编写代码的简单而有效的方法是使用
std::wstring
std::vector

在高级上下文中使用了太多不合适的低级函数,使代码变得可靠。这是我看到的最大问题:

void Files::Push(const File& f)
{
    if(!s_)
    {
        files_ = new File[++s_];
        files_[0] = f;
        return;
    }
    File* tmp = new File[++s_];

    for(int i = 0; i < s_-1; ++i)
    {
        tmp[i] = files_[i];
    }

    tmp[s_-1] = f;

    delete[] files_;
    files_ = tmp;
}
您不能以这种方式使用
memcpy
。首先,您的
File
类中有一个
Files
元素。您的
文件
类中有一个
文件*
。当你对一个
文件
执行
memcpy
操作时,它的地址会改变,破坏了所有你保存的原始指针的位置


尽可能使用值而不是指针。值易于存储和复制,不必删除,也不可悬挂。无偿使用原始指针会失去所有这些好处。

文件的定义是什么?请把你的代码变成一个。std::vector很简单。string很简单。很难错误地使用它们。指针、new、delete和memcpy并不简单。很容易错误地使用它们。你正是成功地做到了这一点。所以,如果你想在家里安装新的架子,你可以拿一把斧头,去树林里砍一棵树?或者你去当地的家装店买现成的木材?这里的
std::vector
也是一样。在这个假定简单的上下文中,您犯了不止一个严重错误。如果我是你,我会非常谨慎地表达对简单和不好的看法。@ ScistNebug我在C++中已经编程了20多年,我永远不会浪费时间去尝试这样的代码,试图让它看起来正确,因为它永远不可靠。学习如何正确处理事情比学习用茶匙制作看似吊桥(但可能会倒塌)的无用技能要好得多。向量和字符串在em内部也使用原始指针。而且它没有被窃听。是的,对于包含文件的文件,我同意,这似乎有点错误。。。哦,是的,还有豆荚。。。Facepalm…@ScienceDiscoveryr关于向量和字符串中的指针,你当然是对的。但是这些课程已经完成了艰苦的工作,为什么不使用它呢?我不明白为什么人们如此讨厌指针。我使用它,因为如果我能掌握它,它是非常强大的工具。是的,确实是这个memcopy失败了。我想把事情简单化,让一切都快一点,看看我进入了什么。。。但好吧,至少我可以从这个错误中吸取教训,希望以后能避免它。。。
Files::Files(const Files& other) : s_(other.s_)
{
    files_ = new File[s_];
    for(int i = 0; i < s_; ++i)
    {
        files_[i] = other.files_[i];
    }
}

Files& Files::operator=(const Files& other)
{
    if(this != &other)
    {
        File* tmp = files_;
        if(other.s_ != s_)
        {
            s_ = other.s_;
            tmp = new File[s_];
        }

        for(int i = 0; i < s_; ++i)
        {
            tmp[i] = other.files_[i];
        }

        delete[] files_;
        files_ = tmp;
    }

    return *this;
}
void Files::Push(const File& f)
{
    if(!s_)
    {
        files_ = new File[++s_];
        files_[0] = f;
        return;
    }
    File* tmp = new File[++s_];

    for(int i = 0; i < s_-1; ++i)
    {
        tmp[i] = files_[i];
    }

    tmp[s_-1] = f;

    delete[] files_;
    files_ = tmp;
}
memcpy(tmp, files_, (s_-1) * sizeof(File));