views:

115

answers:

5

I have class Person as following :

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

Now I need to add two contructors. One taking no arguments, that inserts field values to dynamically allocated resources. Second taking (char*, int) arguments initialized by initialization list. Last part is to define a destructor showing information about destroying objects and deallocating dynamically allocated resources. How to perform this task ?

That's what I already have :

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

    Person(char* c, int i){
    }
};
+3  A: 

In the default constructor, allocation of the char array should include its desired size, e.g.

this->name = new char[32];

Note that this size includes the terminating 0 character, so the effective length of names you can store in this array is 31.

In the parameterized constructor, you can simply assign the given parameters to your class members.

In the destructor, you need to deallocate dynamically allocated resources - make sure to use delete[] when, and only when, deallocating memory allocated with new[]:

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

Update: I missed this one: if you want to allocate age dynamically, you should declare it as int* age.

I assume that the point of this exercise is to practice dynamic allocation/deallocation; in this context, it is fine. However, in general, it is not good practice to dynamically allocate ints, and instead of char* you should almost always use std::string, which handles memory allocation for you automatically and safely.

Péter Török
http://paste.pocoo.org/show/215191/ but it gives me error "invalid conversion from `int*' to `int' " at age.
sasquatch
@sasquatch, see my update.
Péter Török
A: 

You can also allocate just the memory you need to copy the name when you want to set it. Also, don't forget to free the allocated buffer when the object gets destroyed!

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

Edit and answer to remarks :

  • simplified destructor following suggestion by Konrad Rudolf
  • I tend to always set unallocated and deallocated pointers to NULL to avoid picking random memory locations when the pointer is not used right, and unallocated pointers are also easier to spot in the debbuger.
  • I didn't pay attention that the second method was a constructor, I thought it was a setter... changed it.
Stéphane
The destructor can be reduced to the single command `delete [] name;`. The check for `NULL` is unnecessary, as is the assignment.
Konrad Rudolph
The last constructor also has serious problems: `this->name` will be uninitialized at that point which means you can easily end up deleting a garbage pointer. And eventually, `this->name` can't possibly point to any allocated memory, because the constructor is called when an object first comes to existence. - And a further problem, if `c` is NULL, then `this->name` will be left uninitialized.
visitor
+1  A: 

Given your declaration, you cannot initialize age to dynamically allocated memory, since age isn’t a pointer.

You could of course change the type of age to int*. But I wouldn’t do that, it serves no purpose. It’s not clear if the assignment is really asking for dynamic allocation (and if so – why?).

For name, on the other hand, you can proceed as noted by @Péter. But once again, this isn’t a very good solution in most cases because C++ offers the string class which wraps string manipuation nicely into a class. If the assignment permits this, use string in place of char* and dynamic memory allocation.

Konrad Rudolph
+2  A: 

By using the C++ string class you can forget about manual (and dangerous) memory management:

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.
};

Also see this link for the reason why you should always use an initialization list instead of assignments in a constructor.

Vijay Mathew
A: 

I recommend using string class instead of char*.

Something like this:

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;
};
Daniel