我有一个内存泄漏的程序,每次我向代码添加删除它都会崩溃。我只是想知道是否有人知道为什么会这样。崩溃的代码如下。 这是删除的目的地 名字和姓氏声明如下。
char* firstName;
char* lastName;
Name::~Name(){
delete[] firstName;
delete[] lastName;
}
这里是分配内存的地方
Name::Name(Name& name){
//copys the first and last name from one Name to the other
firstName = new char [strlen(name.firstName)+1];
strcpy(firstName,name.firstName);
lastName = new char [strlen(name.lastName)+1];
strcpy(lastName,name.lastName);
}
答案 0 :(得分:1)
您很可能在某个时刻分配了Name
类型的对象,并且没有复制分配(首先我认为没有复制构造函数,但实际上您显示了复制构造函数)。默认生成的副本分配只是按位复制。因此,您会在某个时刻看到指针的双delete[]
(还有内存泄漏,但这不是可见的)。或者,您的其他构造函数如何?有一个默认的构造函数可能没有初始化指针或构造函数可能最终存储指向字符串文字的指针?
最好的方法是不来使用手动内存分配,而是使用std::string
。如果您不能使用std::string
,例如,因为这是一个赋值,我强烈建议您实现自己的简单字符串类:处理多个已分配的实体而不将每个单独包装到合适的资源中维护类非常困难。我不能正确地做到这一点。不可否认,我只用了大约20年的C ++编程。
例如,您的复制构造函数不是异常安全的:如果您的第二个分配因为没有足够的内存来分配而引发异常,则会导致资源泄漏。有一些方法可以处理函数级的try / catch块,但是使用字符串类要容易得多:如果构造函数抛出异常,任何完全构造的子对象都会被自动销毁。这样,字符串的构造函数就会处理内存。
答案 1 :(得分:0)
假设firstName
和lastName
是Name
类的正确元素,您应该注意strlen doesn't check against NULL,因此您应该处理NULL
Name::Name(const Name& name){
if (name.firstName) {
int len_z = strlen(name.firstName)+1;
firstName = new char [len_z];
strncpy(firstName, name.firstName, len_z);
// ^^^ also copy the terminator char ^^^
} else {
firstName = NULL;
}
// repeat for lastName:
if (name.lastName) {
int len_z = strlen(name.lastName)+1;
lastName = new char [len_z];
strncpy(lastName, name.lastName, len_z);
} else {
lastName = NULL;
}
}
或使用如下构造函数创建标准Name
对象:
Name::Name() {
firstName = new char[1];
firstName[0] = '\0';
// repeat for lastName:
lastName = new char[1];
lastName[0] = '\0';
}
至少在这里你看,为什么std::string
是一个更好的选择:它是一个实现你需要的字符串的所有方面的类。如果你手工完成这个,你必须为firstName和lastName加倍所有...并且想象一下middleName
类的下一个版本中将会很快Name
... < / p>