0

我有一个程序存在内存泄漏,每次我在代码中添加删除时它都会崩溃。我只是想知道是否有人知道为什么会这样。崩溃的代码如下。这是带有删除名字和姓氏的析构函数,声明如下。

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

}
4

2 回答 2

1

很可能您Name在某个时候分配了您类型的对象并且没有复制分配(首先我认为没有复制构造函数,但您实际上显示了您的复制构造函数)。默认生成的复制分配只是按位复制。结果,您会delete[]在某个时候看到双倍的指针(还有内存泄漏,但这并不明显)。或者,您的其他构造函数如何?是否有可能没有初始化指针的默认构造函数或可能最终存储指向字符串文字的指针的构造函数?

最好的方法不是使用手动内存分配,而是使用std::string. 如果您不能使用std::string,例如,因为这是一个分配,我强烈建议您实现自己的简单字符串类:处理多个分配的实体而不将每个实体单独包装到合适的资源维护类中是非常困难的。我不能正确地做到这一点。诚然,大约 20 年以来,我只使用 C++ 编程。

例如,您的复制构造函数不是异常安全的:如果您的第二次分配由于没有足够的内存可以分配而引发异常,那么您就有资源泄漏。有一些方法可以处理函数级的 try/catch 块,但使用字符串类要容易得多:如果构造函数抛出异常,任何完全构造的子对象都会自动销毁。这样,字符串的构造函数会处理内存。

于 2013-11-09T22:46:41.320 回答
0

假设firstNameandlastName是你的类的正确元素Name,你应该注意strlen 不会检查 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...

于 2013-11-09T23:41:04.457 回答