在c ++中复制和删除

时间:2016-12-30 17:29:00

标签: c++

我的班级名为“学生”,有3名成员。

此外,我还有2个功能,SetNameOperator=

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函数,我有更多问题。

我不知道如何解决这个问题。 有人可以帮我或提示吗?

4 个答案:

答案 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风格的字符串。

相关问题