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