【问题标题】:Constructors for C++ objectsC++ 对象的构造函数
【发布时间】:2011-02-20 19:40:03
【问题描述】:

我的 Person 类如下:

class Person {   
    char* name;
    int age;
};

现在我需要添加两个构造函数。一种不带参数,将字段值插入动态分配的资源。第二次采用由初始化列表初始化的 (char*, int) 参数。最后一部分是定义一个析构函数,显示有关销毁对象和重新分配动态分配的资源的信息。如何执行此任务?

这就是我已经拥有的:

class Person {   
    char* name;
    int age;
public:
    Person(){
        this->name = new *char;
        this->age = new int;
    }

    Person(char* c, int i){
    }
};

【问题讨论】:

    标签: c++ dynamic-memory-allocation


    【解决方案1】:

    您还可以在需要设置名称时仅分配复制名称所需的内存。 另外,不要忘记在对象被销毁时释放分配的缓冲区!

    class Person {   
        char* name;
        int age;
    public:
        Person(){
            this->name = NULL;
            this->age = 0; // no need to allocate memory for basic types
        }
    
        ~Person(){
            delete [] name;
        }
    
        set(char* c, int i){
            this->age = i;
    
            // copy name if input pointer name is valid
            if (c != NULL){
                // if memory have already been allocated : delete first
                if (this->name != NULL){
                    delete [] name;
                    name = NULL;
                }
                // allocate memory : 1 more char for the trailing '\0'
                this->name = new char[strlen(c)+1];
                // copy string
                strcpy(this->name,c);
            }
        }
    };
    

    编辑并回复评论:

    • 根据 Konrad Rudolf 的建议简化了析构函数
    • 我倾向于始终将未分配和已解除分配的指针设置为 NULL,以避免在未正确使用指针时选择随机内存位置,并且在调试器中也更容易发现未分配的指针。
    • 没注意第二个方法是构造函数,还以为是setter呢……改了。

    【讨论】:

    • 析构函数可以简化为单个命令delete [] name;NULL 的检查是不必要的,分配也是如此。
    • 最后一个构造函数也有严重的问题:this->name 将在此时未初始化,这意味着您可以轻松地最终删除垃圾指针。最终,this->name 不可能指向任何分配的内存,因为构造函数在对象首次存在时被调用。 - 还有一个问题,如果c 为NULL,那么this->name 将保持未初始化状态。
    【解决方案2】:

    我建议使用字符串类而不是 char*。

    类似这样的:

    class Person
    {
     public:
      Person() : name(""), age(0) {}
      Person(const string& n, int a) : name(n), age(a) {}
    
      // whatever here.
    
      ~Person() {} // do nothing
    
     private:
      string name;
      int age;
    };
    

    【讨论】:

      【解决方案3】:

      在默认构造函数中,char数组的分配应该包括它想要的大小,例如

      this->name = new char[32];
      

      请注意,此大小包括终止字符 0,因此您可以存储在此数组中的名称的有效长度为 31。

      在参数化构造函数中,您可以简单地将给定的参数分配给您的类成员。

      在析构函数中,您需要释放动态分配的资源 - 确保在且仅在释放使用new[] 分配的内存时使用delete[]

      ~Person(){
          std::cout << "Destroying resources" << std::endl;
          delete[] name;
          delete age;
      }
      

      更新:我错过了这个:如果你想动态分配age,你应该声明它为int* age

      我认为本练习的重点是练习动态分配/解除分配;在这种情况下,这很好。但是,一般来说,动态分配ints 并不是一个好习惯,您几乎应该总是使用std::string 而不是char*,它会自动安全地为您处理内存分配。

      【讨论】:

      【解决方案4】:

      通过使用 C++ string 类,您可以忘记手动(且危险的)内存管理:

      class Person {
          public:
              Person () : name_(""), age_(0) { }
              Person (const std::string& name, int age) : name_(name), age_(age) { }
          // There is no need for the destructor as the memory is managed by the string class.
      };
      

      还有see this link,因为您应该始终在构造函数中使用初始化列表而不是赋值。

      【讨论】:

        【解决方案5】:

        根据您的声明,您不能age 初始化为动态分配的内存,因为 age 不是指针。

        您当然可以将age 的类型更改为int*。但我不会这样做,它没有任何意义。目前尚不清楚该分配是否真的要求动态分配(如果是这样 - 为什么?)。

        另一方面,对于name,您可以按照@Péter 的说明进行操作。但是,在大多数情况下,这又不是一个很好的解决方案,因为 C++ 提供了string 类,它将字符串操作很好地包装到一个类中。如果分配允许这样做,请使用string 代替char* 和动态内存分配。

        【讨论】:

          猜你喜欢
          • 2010-09-28
          • 2012-02-05
          • 1970-01-01
          • 2013-10-20
          • 2021-10-22
          • 1970-01-01
          • 2013-08-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多