我的班级名为“学生”,有3名成员。
此外,我还有2个功能,SetName
和Operator=
。
class Student
{
private:
int ID;
char* name;
Faculty faculty;
public :
bool SetName(const char* other);
};
typedef enum { ENGINEERING, MEDICINE, HUMANITIES, MANAGEMENT, GENERAL } Faculty;
bool Student::SetName(const char * other)
{
if (!other)
return false;
char* temp;
temp = new char[strlen(other) + 1];
if (!temp)
return false;
//if (this->name)
// delete[]name;
std::string s = other;
name = temp;
memcpy(name,other,strlen(other) + 1);
return true;
}
Student& Student::operator=(const Student &other)
{
this->ID = other.ID;
this->faculty = other.faculty;
this->SetName(other.name);
return *this;
};
当然,我有默认和复制析构函数。 “SetName”函数存在问题,但是当我运行valgrind时,它告诉我 -
==4661== HEAP SUMMARY:
==4661== in use at exit: 72,710 bytes in 2 blocks
==4661== total heap usage: 47 allocs, 45 frees, 74,410 bytes allocated
==4661==
==4661== 6 bytes in 1 blocks are definitely lost in loss record 1 of 2
==4661== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4661== by 0x402798: Student::SetName(char const*) (in /home/noam/Desktop/Avoda3/temp/myStudentSet)
==4661== by 0x40264E: Student::Student(Student const&) (in /home/noam/Desktop/Avoda3/temp/myStudentSet)
==4661== by 0x4011D6: StudentSet::Add(Student const&) (in /home/noam/Desktop/Avoda3/temp/myStudentSet)
==4661== by 0x400F1D: StudentSet::StudentSet(Student const*, int) (in /home/noam/Desktop/Avoda3/temp/myStudentSet)
==4661== by 0x4020B6: main (in /home/noam/Desktop/Avoda3/temp/myStudentSet)
==4661==
==4661== LEAK SUMMARY:
==4661== definitely lost: 6 bytes in 1 blocks
==4661== indirectly lost: 0 bytes in 0 blocks
==4661== possibly lost: 0 bytes in 0 blocks
==4661== still reachable: 72,704 bytes in 1 blocks
==4661== suppressed: 0 bytes in 0 blocks
==4661== Reachable blocks (those to which a pointer was found) are not shown.
==4661== To see them, rerun with: --leak-check=full --show-leak-kinds=all
当我尝试删除评论并添加
时 if (this->name)
delete[]name;
到SetName
函数,我有更多问题。
我不知道如何解决这个问题。 有人可以帮我或提示吗?
答案 0 :(得分:3)
目前,我认为使用char *
您应该更喜欢学习如何使用c ++工具。第一个建议,使用std::string
会更好。
但是如果你坚持自己管理内存,你会删除类析构函数中的内存。
~Student( ) { delete[ ] name; }
这样它就可以在你的类对象的任何范围内存活。但是如果你没有打电话给SetName(...)
怎么办?然后名称指向的垃圾不可删除。
class Student
:name( nullptr )
{
~Student( ) { delete[ ] name; }
....
现在,如果您不使用SetName(...),则不会尝试删除未知的内容。
答案 1 :(得分:1)
问题是当创建的Student对象超出范围(被破坏)时,不会删除为该名称分配的内存。向类中添加析构函数,在构造函数中将名称指针初始化为NULL,并在析构函数中对其进行测试。如果不是NULL,则删除[]。祝你好运,你的代码也可能需要一些清理,但这是另一个故事。
答案 2 :(得分:0)
如果你想坚持使用前C + 11 C ++的混合。您需要确保构造函数,赋值运算符和析构函数正确管理内存。以下代码在valgrid
下运行,没有任何泄漏:
#include <string.h>
typedef enum { ENGINEERING, MEDICINE, HUMANITIES, MANAGEMENT, GENERAL } Faculty;
class Student
{
private:
int ID;
char* name;
Faculty faculty;
public :
Student() : name(0) {}
~Student() {
if (name)
delete [] name;
}
bool SetName(const char* other);
};
bool Student::SetName(const char * other)
{
if (!other)
return false;
const int len_other_with_null = strlen(other) + 1;
char *temp = new char[len_other_with_null];
if (!temp) {
return false;
}
if (this->name)
delete [] name;
name = temp;
memcpy(name, other, len_other_with_null);
return true;
}
int main(int argc, char ** argv) {
Student student;
student.SetName("Hi");
return 0;
}
答案 3 :(得分:0)
您遇到的delete []
名称问题是创建没有名称的学生的直接结果。
Student student; // student.name is uninitialized. Accessing its value
// would be undefined behaviour.
当你第一次尝试使用SetName
时,你有一个未初始化的值,删除它会导致崩溃;所以你忽略了delete[]
,这会导致内存泄漏。
也许你希望student.name
作为空指针开始它的生命,但这不是C ++的定义方式。你必须自己做。
惯用的C ++方法是在构造函数中初始化它。
class Student {
public:
Student : name(nullptr) {}
...
现在您可以取消注释delete
让这个bug对你来说是一个重要的教训。始终为您的类编写构造函数,并始终初始化其中的所有数据成员。
这将我们带到下一点。你如何初始化ID和教师?它们没有默认的“空”值。即使有,一个没有身份证和没有能力的学生是某种鬼,我们不想处理。
惯用的C ++方法是将这些值作为参数传递给构造函数。
class Student {
public:
Student (int ID_, Faculty faculty_) :
name(nullptr), ID(ID_), faculty(faculty_) {}
..
但是等等,我们创造了一个未命名的学生,这可能会导致各种各样的问题。也许将名称传递给构造函数?
class Student {
public:
Student (const char* name_, int ID_, Faculty faculty_) :
name(nullptr), ID(ID_), faculty(faculty_) {
SetName(name_);
}
...
现在这是一个我们可以引以为傲的学生......除了一件事。我们仍然可以传递空指针作为名称,学生将无名。在SetName
中,您通过返回false
来指示失败来处理它。构造函数不返回值。怎么办?
惯用的C ++方式是抛出异常。
class Student {
public:
Student (const char* name_, int ID_, Faculty faculty_) :
name(nullptr), ID(ID_), faculty(faculty_) {
if (!name_)
throw std::domain_error("Null name passed to Student::Student");
SetName(name_);
}
...
根据三条规则,你的班级应该有一个复制构造函数:
class Student {
public:
Student(const Student& other) :
Student(other.name, other.ID, other.faculty) {}
Student (const char* name_, int ID_, Faculty faculty_) :
name(nullptr), ID(ID_), faculty(faculty_) {
if (!name_)
throw std::domain_error("Null name passed to Student::Student");
SetName(name_);
}
当然,在实际代码中,您希望使用std::string
而不是手动管理C风格的字符串。